aiobungie

A Pythonic async/await wrapper for interacting with the Bungie API.

Base client.

Example
import aiobungie

client = aiobungie.Client('YOUR_API_KEY')

# Search for Destiny2 users.
async def main() -> None:
    users = await client.search_users('Crit')

    # Iterate over the users and take the first 5 results.
    for user in users.take(5):
        print(f'{user.name} ({user.code})')

        # Iterate through the users memberships.
        for membership in user.memberships:
            print(membership.type, membership.id)

client.run(main()) # or asyncio.run(main())

Single RESTClient instance.

The difference between base client and the REST clients:

  • No Hight-Level concepts.
  • All returned data are pure JSON objects from the API.
  • No object creation.
Example
import aiobungie

async def main() -> None:
    # Using `async with` context manager to close the session properly.
    async with aiobungie.RESTClient("TOKEN") as rest:
        payload = await rest.fetch_player('Fate怒', 4275)

        for membership in payload:
            print(membership['membershipId'], membership['iconPath'])

import asyncio
asyncio.run(main())

REST client pool.

A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")

async def func1() -> None:
    async with pool.acquire() as instance:
        tokens = await instance.fetch_oauth2_tokens('code')
        pool.metadata['tokens'] = tokens

# Other instance may access the tokens from pool since its shared.

async def func2() -> None:
    async with pool.acquire() as instance:
        tokens = pool.metadata['tokens']
        tokens = await instance.refresh_access_token(tokens.refresh_token)

async def main() -> None:
    await asyncio.gather(func1(), func2())

asyncio.run(main())

Should you use the base client or the REST client? This returns to you. For an example if you're building a website.

You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.

Or of you're building a Discord bot for an example or something simple. The base client is the way to go.

  1# MIT License
  2#
  3# Copyright (c) 2020 - Present nxtlo
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a copy
  6# of this software and associated documentation files (the "Software"), to deal
  7# in the Software without restriction, including without limitation the rights
  8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9# copies of the Software, and to permit persons to whom the Software is
 10# furnished to do so, subject to the following conditions:
 11#
 12# The above copyright notice and this permission notice shall be included in all
 13# copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21# SOFTWARE.
 22
 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API.
 24
 25Base client.
 26
 27Example
 28-------
 29```py
 30import aiobungie
 31
 32client = aiobungie.Client('YOUR_API_KEY')
 33
 34# Search for Destiny2 users.
 35async def main() -> None:
 36    users = await client.search_users('Crit')
 37
 38    # Iterate over the users and take the first 5 results.
 39    for user in users.take(5):
 40        print(f'{user.name} ({user.code})')
 41
 42        # Iterate through the users memberships.
 43        for membership in user.memberships:
 44            print(membership.type, membership.id)
 45
 46client.run(main()) # or asyncio.run(main())
 47```
 48
 49Single RESTClient instance.
 50
 51The difference between base client and the REST clients:
 52
 53* No Hight-Level concepts.
 54* All returned data are pure JSON objects from the API.
 55* No object creation.
 56
 57Example
 58-------
 59```py
 60import aiobungie
 61
 62async def main() -> None:
 63    # Using `async with` context manager to close the session properly.
 64    async with aiobungie.RESTClient("TOKEN") as rest:
 65        payload = await rest.fetch_player('Fate怒', 4275)
 66
 67        for membership in payload:
 68            print(membership['membershipId'], membership['iconPath'])
 69
 70import asyncio
 71asyncio.run(main())
 72```
 73
 74REST client pool.
 75
 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection.
 77
 78Example
 79-------
 80```py
 81import aiobungie
 82import asyncio
 83
 84pool = aiobungie.RESTPool("token")
 85
 86async def func1() -> None:
 87    async with pool.acquire() as instance:
 88        tokens = await instance.fetch_oauth2_tokens('code')
 89        pool.metadata['tokens'] = tokens
 90
 91# Other instance may access the tokens from pool since its shared.
 92
 93async def func2() -> None:
 94    async with pool.acquire() as instance:
 95        tokens = pool.metadata['tokens']
 96        tokens = await instance.refresh_access_token(tokens.refresh_token)
 97
 98async def main() -> None:
 99    await asyncio.gather(func1(), func2())
100
101asyncio.run(main())
102```
103
104Should you use the base client or the REST client?
105This returns to you. For an example if you're building a website.
106
107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects.
108Which gives you the freedom to deserialize it and implement your own logic in the front-end.
109
110Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
111"""
112
113
114from __future__ import annotations
115
116from aiobungie import builders
117from aiobungie import crates
118from aiobungie import interfaces
119from aiobungie import traits
120from aiobungie import typedefs
121from aiobungie import url
122from aiobungie.client import Client
123from aiobungie.error import *
124from aiobungie.internal import iterators
125from aiobungie.internal.assets import Image
126from aiobungie.internal.enums import *
127from aiobungie.internal.factory import Factory
128from aiobungie.internal.iterators import *
129from aiobungie.rest import *
130from aiobungie.undefined import Undefined
131from aiobungie.undefined import UndefinedOr
132from aiobungie.undefined import UndefinedType
133
134from ._info import __about__
135from ._info import __author__
136from ._info import __docs__
137from ._info import __email__
138from ._info import __license__
139from ._info import __url__
140from ._info import __version__
141
142# Alias for crate for backwards compatibility.
143crate = crates
144
145# Activity enums
146from .crates.activity import Difficulty
147
148# Components enums
149from .crates.components import ComponentFields
150from .crates.components import ComponentPrivacy
151
152# Entity enums
153from .crates.entity import GatingScope
154from .crates.entity import ObjectiveUIStyle
155from .crates.entity import ValueUIStyle
156
157# Fireteam enums.
158from .crates.fireteams import FireteamActivity
159from .crates.fireteams import FireteamDate
160from .crates.fireteams import FireteamLanguage
161from .crates.fireteams import FireteamPlatform
162
163# Records enums
164from .crates.records import RecordState
165
166__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
60@attrs.define(auto_exc=True)
61class AiobungieError(RuntimeError):
62    """Base exception class that all other errors inherit from."""

Base exception class that all other errors inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
646@typing.final
647class AmmoType(int, Enum):
648    """AN enum for Detyiny 2 ammo types."""
649
650    NONE = 0
651    PRIMARY = 1
652    SPECIAL = 2
653    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
160@attrs.define(auto_exc=True)
161class BadRequest(HTTPError):
162    """Bad requests exceptions."""
163
164    url: typing.Optional[typedefs.StrOrURL]
165    """The URL/endpoint caused this error."""
166
167    body: typing.Any
168    """The response body."""
169
170    headers: multidict.CIMultiDictProxy[str]
171    """The response headers."""
172
173    http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)

Bad requests exceptions.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>)
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = http_status
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
args
def CharacterError(message: str, http_status: http.HTTPStatus) -> None:
76@helpers.deprecated("o.2.5", removed_in="0.2.6")
77@attrs.define(auto_exc=True)
78class CharacterError(HTTPError):
79    """Raised when a encountering making a character-based request.
80
81    .. warning::
82        This is deprecated since 0.2.5 and will be removed in 0.2.6.
83    """

Raised when a encountering making a character-based request.

This is deprecated since 0.2.5 and will be removed in 0.2.6.

@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
701@typing.final
702class ClanMemberType(int, Enum):
703    """An enum for bungie clan member types."""
704
705    NONE = 0
706    BEGINNER = 1
707    MEMBER = 2
708    ADMIN = 3
709    ACTING_FOUNDER = 4
710    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
477@typing.final
478class Class(int, Enum):
479    """An Enum for Destiny character classes."""
480
481    TITAN = 0
482    HUNTER = 1
483    WARLOCK = 2
484    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  61class Client(traits.ClientApp):
  62    """Standard Bungie API client application.
  63
  64    This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory`
  65    and returns `aiobungie.crates` Python object implementations of the responses.
  66
  67    A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts.
  68
  69    Parameters
  70    -----------
  71    token: `str`
  72        Your Bungie's API key or Token from the developer's portal.
  73
  74    Other Parameters
  75    ----------------
  76    rest_client: `aiobungie.interfaces.RESTInterface | None`
  77        An optional rest client instance you can pass.
  78        If set to `None` then the client will use the default instance.
  79
  80    Example
  81    -------
  82    ```py
  83    TOKEN = "SOME_TOKEN"
  84    async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client:
  85        client = aiobungie.Client(TOKEN, rest_client=rest_client)
  86    ```
  87
  88    max_retries : `int`
  89        The max retries number to retry if the request hit a `5xx` status code.
  90    max_ratelimit_retries : `int`
  91        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
  92    client_secret : `str | None`
  93        An optional application client secret,
  94        This is only needed if you're fetching OAuth2 tokens with this client.
  95    client_id : `int | None`
  96        An optional application client id,
  97        This is only needed if you're fetching OAuth2 tokens with this client.
  98    """
  99
 100    __slots__ = ("_rest", "_factory", "_client_secret", "_client_id")
 101
 102    def __init__(
 103        self,
 104        token: str,
 105        /,
 106        client_secret: typing.Optional[str] = None,
 107        client_id: typing.Optional[int] = None,
 108        *,
 109        rest_client: typing.Optional[interfaces.RESTInterface] = None,
 110        max_retries: int = 4,
 111        max_ratelimit_retries: int = 3,
 112    ) -> None:
 113
 114        self._client_secret = client_secret
 115        self._client_id = client_id
 116
 117        self._rest = (
 118            rest_client
 119            if rest_client is not None
 120            else rest_.RESTClient(
 121                token,
 122                client_secret,
 123                client_id,
 124                max_retries=max_retries,
 125                max_ratelimit_retries=max_ratelimit_retries,
 126            )
 127        )
 128
 129        self._factory = factory_.Factory(self)
 130
 131    @property
 132    def factory(self) -> factory_.Factory:
 133        return self._factory
 134
 135    @property
 136    def rest(self) -> interfaces.RESTInterface:
 137        return self._rest
 138
 139    @property
 140    def request(self) -> Client:
 141        return copy.copy(self)
 142
 143    @property
 144    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 145        return self._rest.metadata
 146
 147    def run(
 148        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
 149    ) -> None:
 150        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
 151        try:
 152            if not loop.is_running():
 153                loop.set_debug(debug)
 154                loop.run_until_complete(future)
 155
 156        except Exception as exc:
 157            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
 158
 159        except KeyboardInterrupt:
 160            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
 161            return
 162
 163        finally:
 164            if self._rest.is_alive:
 165                # Clean up sessions.
 166                loop.run_until_complete(self._rest.close())
 167
 168    # * User methods.
 169
 170    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 171        """Fetch and return a user object of the bungie net user associated with account.
 172
 173        .. warning::
 174            This method requires OAuth2 scope and a Bearer access token.
 175
 176        Parameters
 177        ----------
 178        access_token : `str`
 179            A valid Bearer access token for the authorization.
 180
 181        Returns
 182        -------
 183        `aiobungie.crates.user.User`
 184            A user object includes the Destiny memberships and Bungie.net user.
 185        """
 186        resp = await self.rest.fetch_current_user_memberships(access_token)
 187
 188        return self.factory.deserialize_user(resp)
 189
 190    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 191        """Fetch a Bungie user by their BungieNet id.
 192
 193        .. note::
 194            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 195            for other memberships.
 196
 197        Parameters
 198        ----------
 199        id: `int`
 200            The user id.
 201
 202        Returns
 203        -------
 204        `aiobungie.crates.user.BungieUser`
 205            A Bungie user.
 206
 207        Raises
 208        ------
 209        `aiobungie.error.NotFound`
 210            The user was not found.
 211        """
 212        payload = await self.rest.fetch_bungie_user(id)
 213
 214        return self.factory.deserialize_bungie_user(payload)
 215
 216    async def search_users(
 217        self, name: str, /
 218    ) -> iterators.FlatIterator[user.SearchableDestinyUser]:
 219        """Search for players and return all players that matches the same name.
 220
 221        Parameters
 222        ----------
 223        name : `buildins.str`
 224            The user name.
 225
 226        Returns
 227        -------
 228        `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]`
 229            A sequence of destiny memberships.
 230        """
 231        payload = await self.rest.search_users(name)
 232
 233        return iterators.FlatIterator(
 234            [
 235                self.factory.deserialize_searched_user(user)
 236                for user in payload["searchResults"]
 237            ]
 238        )
 239
 240    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 241        """Fetch all available user themes.
 242
 243        Returns
 244        -------
 245        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 246            A sequence of user themes.
 247        """
 248        data = await self.rest.fetch_user_themes()
 249
 250        return self.factory.deserialize_user_themes(data)
 251
 252    async def fetch_hard_types(
 253        self,
 254        credential: int,
 255        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 256        /,
 257    ) -> user.HardLinkedMembership:
 258        """Gets any hard linked membership given a credential.
 259        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 260        Cross Save aware.
 261
 262        Parameters
 263        ----------
 264        credential: `int`
 265            A valid SteamID64
 266        type: `aiobungie.CredentialType`
 267            The credential type. This must not be changed
 268            Since its only credential that works "currently"
 269
 270        Returns
 271        -------
 272        `aiobungie.crates.user.HardLinkedMembership`
 273            Information about the hard linked data.
 274        """
 275
 276        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 277
 278        return user.HardLinkedMembership(
 279            id=int(payload["membershipId"]),
 280            type=enums.MembershipType(payload["membershipType"]),
 281            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 282        )
 283
 284    async def fetch_membership_from_id(
 285        self,
 286        id: int,
 287        /,
 288        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 289    ) -> user.User:
 290        """Fetch Bungie user's memberships from their id.
 291
 292        Notes
 293        -----
 294        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 295        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 296        see `aiobungie.crates.user.DestinyMembership` for more details.
 297        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 298
 299        Parameters
 300        ----------
 301        id : `int`
 302            The user's id.
 303        type : `aiobungie.MembershipType`
 304            The user's membership type.
 305
 306        Returns
 307        -------
 308        `aiobungie.crates.User`
 309            A Bungie user with their membership types.
 310
 311        Raises
 312        ------
 313        aiobungie.NotFound
 314            The requested user was not found.
 315        """
 316        payload = await self.rest.fetch_membership_from_id(id, type)
 317
 318        return self.factory.deserialize_user(payload)
 319
 320    async def fetch_user_credentials(
 321        self, access_token: str, membership_id: int, /
 322    ) -> collections.Sequence[user.UserCredentials]:
 323        """Fetch an array of credential types attached to the requested account.
 324
 325        .. note::
 326            This method require OAuth2 Bearer access token.
 327
 328        Parameters
 329        ----------
 330        access_token : `str`
 331            The bearer access token associated with the bungie account.
 332        membership_id : `int`
 333            The id of the membership to return.
 334
 335        Returns
 336        -------
 337        `collections.Sequence[aiobungie.crates.UserCredentials]`
 338            A sequence of the attached user credentials.
 339
 340        Raises
 341        ------
 342        `aiobungie.Unauthorized`
 343            The access token was wrong or no access token passed.
 344        """
 345        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 346
 347        return self.factory.deserialize_user_credentials(resp)
 348
 349    # * Destiny 2.
 350
 351    async def fetch_profile(
 352        self,
 353        member_id: int,
 354        type: typedefs.IntAnd[enums.MembershipType],
 355        components: list[enums.ComponentType],
 356        auth: typing.Optional[str] = None,
 357    ) -> components.Component:
 358        """
 359        Fetch a bungie profile passing components to the request.
 360
 361        Parameters
 362        ----------
 363        member_id: `int`
 364            The member's id.
 365        type: `aiobungie.MembershipType`
 366            A valid membership type.
 367        components : `list[aiobungie.ComponentType]`
 368            List of profile components to collect and return.
 369
 370        Other Parameters
 371        ----------------
 372        auth : `typing.Optional[str]`
 373            A Bearer access_token to make the request with.
 374            This is optional and limited to components that only requires an Authorization token.
 375
 376        Returns
 377        --------
 378        `aiobungie.crates.Component`
 379            A Destiny 2 player profile with its components.
 380            Only passed components will be available if they exists. Otherwise they will be `None`
 381
 382        Raises
 383        ------
 384        `aiobungie.MembershipTypeError`
 385            The provided membership type was invalid.
 386        """
 387        data = await self.rest.fetch_profile(member_id, type, components, auth)
 388        return self.factory.deserialize_components(data)
 389
 390    async def fetch_linked_profiles(
 391        self,
 392        member_id: int,
 393        member_type: typedefs.IntAnd[enums.MembershipType],
 394        /,
 395        *,
 396        all: bool = False,
 397    ) -> profile.LinkedProfile:
 398        """Returns a summary information about all profiles linked to the requested member.
 399
 400        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 401
 402        .. note::
 403            It will only return linked accounts whose linkages you are allowed to view.
 404
 405        Parameters
 406        ----------
 407        member_id : `int`
 408            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 409        member_type : `aiobungie.MembershipType`
 410            The type for the membership whose linked Destiny account you want to return.
 411
 412        Other Parameters
 413        ----------------
 414        all : `bool`
 415            If provided and set to `True`, All memberships regardless
 416            of whether they're obscured by overrides will be returned,
 417
 418            If provided and set to `False`, Only available memberships will be returned.
 419            The default for this is `False`.
 420
 421        Returns
 422        -------
 423        `aiobungie.crates.profile.LinkedProfile`
 424            A linked profile object.
 425        """
 426        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 427
 428        return self.factory.deserialize_linked_profiles(resp)
 429
 430    async def fetch_player(
 431        self,
 432        name: str,
 433        code: int,
 434        /,
 435        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 436    ) -> collections.Sequence[user.DestinyMembership]:
 437        """Fetch a Destiny 2 player's memberships.
 438
 439        Parameters
 440        -----------
 441        name: `str`
 442            The unique Bungie player name.
 443        code : `int`
 444            The unique Bungie display name code.
 445        type: `aiobungie.internal.enums.MembershipType`
 446            The player's membership type, e,g. XBOX, STEAM, PSN
 447
 448        Returns
 449        --------
 450        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 451            A sequence of the found Destiny 2 player memberships.
 452            An empty sequence will be returned if no one found.
 453
 454        Raises
 455        ------
 456        `aiobungie.MembershipTypeError`
 457            The provided membership type was invalid.
 458        """
 459        resp = await self.rest.fetch_player(name, code, type)
 460
 461        return self.factory.deserialize_destiny_memberships(resp)
 462
 463    async def fetch_character(
 464        self,
 465        member_id: int,
 466        membership_type: typedefs.IntAnd[enums.MembershipType],
 467        character_id: int,
 468        components: list[enums.ComponentType],
 469        auth: typing.Optional[str] = None,
 470    ) -> components.CharacterComponent:
 471        """Fetch a Destiny 2 character.
 472
 473        Parameters
 474        ----------
 475        member_id: `int`
 476            A valid bungie member id.
 477        character_id: `int`
 478            The Destiny character id to retrieve.
 479        membership_type: `aiobungie.internal.enums.MembershipType`
 480            The member's membership type.
 481        components: `list[aiobungie.ComponentType]`
 482            Multiple arguments of character components to collect and return.
 483
 484        Other Parameters
 485        ----------------
 486        auth : `typing.Optional[str]`
 487            A Bearer access_token to make the request with.
 488            This is optional and limited to components that only requires an Authorization token.
 489
 490        Returns
 491        -------
 492        `aiobungie.crates.CharacterComponent`
 493            A Bungie character component.
 494
 495        `aiobungie.MembershipTypeError`
 496            The provided membership type was invalid.
 497        """
 498        resp = await self.rest.fetch_character(
 499            member_id, membership_type, character_id, components, auth
 500        )
 501
 502        return self.factory.deserialize_character_component(resp)
 503
 504    async def fetch_unique_weapon_history(
 505        self,
 506        membership_id: int,
 507        character_id: int,
 508        membership_type: typedefs.IntAnd[enums.MembershipType],
 509    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 510        """Fetch details about unique weapon usage for a character. Includes all exotics.
 511
 512        Parameters
 513        ----------
 514        membership_id : `int`
 515            The Destiny user membership id.
 516        character_id : `int`
 517            The character id to retrieve.
 518        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 519            The Destiny user's membership type.
 520
 521        Returns
 522        -------
 523        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 524            A sequence of the weapon's extended values.
 525        """
 526        resp = await self._rest.fetch_unique_weapon_history(
 527            membership_id, character_id, membership_type
 528        )
 529
 530        return [
 531            self._factory.deserialize_extended_weapon_values(weapon)
 532            for weapon in resp["weapons"]
 533        ]
 534
 535    # * Destiny 2 Activities.
 536
 537    async def fetch_activities(
 538        self,
 539        member_id: int,
 540        character_id: int,
 541        mode: typedefs.IntAnd[enums.GameMode],
 542        *,
 543        membership_type: typedefs.IntAnd[
 544            enums.MembershipType
 545        ] = enums.MembershipType.ALL,
 546        page: int = 0,
 547        limit: int = 250,
 548    ) -> iterators.FlatIterator[activity.Activity]:
 549        """Fetch a Destiny 2 activity for the specified character id.
 550
 551        Parameters
 552        ----------
 553        member_id: `int`
 554            The user id that starts with `4611`.
 555        character_id: `int`
 556            The id of the character to retrieve the activities for.
 557        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
 558            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 559
 560        Other Parameters
 561        ----------------
 562        membership_type: `aiobungie.internal.enums.MembershipType`
 563            The Member ship type, if nothing was passed than it will return all.
 564        page: int
 565            The page number. Default is `0`
 566        limit: int
 567            Limit the returned result. Default is `250`.
 568
 569        Returns
 570        -------
 571        `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]`
 572            An iterator of the player's activities.
 573
 574        Raises
 575        ------
 576        `aiobungie.MembershipTypeError`
 577            The provided membership type was invalid.
 578        """
 579        resp = await self.rest.fetch_activities(
 580            member_id,
 581            character_id,
 582            mode,
 583            membership_type=membership_type,
 584            page=page,
 585            limit=limit,
 586        )
 587
 588        return self.factory.deserialize_activities(resp)
 589
 590    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 591        """Fetch a post activity details.
 592
 593        Parameters
 594        ----------
 595        instance_id: `int`
 596            The activity instance id.
 597
 598        Returns
 599        -------
 600        `aiobungie.crates.PostActivity`
 601           A post activity object.
 602        """
 603        resp = await self.rest.fetch_post_activity(instance_id)
 604
 605        return self.factory.deserialize_post_activity(resp)
 606
 607    async def fetch_aggregated_activity_stats(
 608        self,
 609        character_id: int,
 610        membership_id: int,
 611        membership_type: typedefs.IntAnd[enums.MembershipType],
 612    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
 613        """Fetch aggregated activity stats for a character.
 614
 615        Parameters
 616        ----------
 617        character_id: `int`
 618            The id of the character to retrieve the activities for.
 619        membership_id: `int`
 620            The id of the user that started with `4611`.
 621        membership_type: `aiobungie.internal.enums.MembershipType`
 622            The Member ship type.
 623
 624        Returns
 625        -------
 626        `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]`
 627            An iterator of the player's activities.
 628
 629        Raises
 630        ------
 631        `aiobungie.MembershipTypeError`
 632            The provided membership type was invalid.
 633        """
 634        resp = await self.rest.fetch_aggregated_activity_stats(
 635            character_id, membership_id, membership_type
 636        )
 637
 638        return self.factory.deserialize_aggregated_activities(resp)
 639
 640    # * Destiny 2 Clans or GroupsV2.
 641
 642    async def fetch_clan_from_id(
 643        self,
 644        id: int,
 645        /,
 646        access_token: typing.Optional[str] = None,
 647    ) -> clans.Clan:
 648        """Fetch a Bungie Clan by its id.
 649
 650        Parameters
 651        -----------
 652        id: `int`
 653            The clan id.
 654
 655        Returns
 656        --------
 657        `aiobungie.crates.Clan`
 658            An Bungie clan.
 659
 660        Raises
 661        ------
 662        `aiobungie.NotFound`
 663            The clan was not found.
 664        """
 665        resp = await self.rest.fetch_clan_from_id(id, access_token)
 666
 667        return self.factory.deserialize_clan(resp)
 668
 669    async def fetch_clan(
 670        self,
 671        name: str,
 672        /,
 673        access_token: typing.Optional[str] = None,
 674        *,
 675        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 676    ) -> clans.Clan:
 677        """Fetch a Clan by its name.
 678        This method will return the first clan found with given name.
 679
 680        Parameters
 681        ----------
 682        name: `str`
 683            The clan name
 684
 685        Other Parameters
 686        ----------------
 687        access_token : `typing.Optional[str]`
 688            An optional access token to make the request with.
 689
 690            If the token was bound to a member of the clan,
 691            This field `aiobungie.crates.Clan.current_user_membership` will be available
 692            and will return the membership of the user who made this request.
 693        type : `aiobungie.GroupType`
 694            The group type, Default is aiobungie.GroupType.CLAN.
 695
 696        Returns
 697        -------
 698        `aiobungie.crates.Clan`
 699            A Bungie clan.
 700
 701        Raises
 702        ------
 703        `aiobungie.NotFound`
 704            The clan was not found.
 705        """
 706        resp = await self.rest.fetch_clan(name, access_token, type=type)
 707
 708        return self.factory.deserialize_clan(resp)
 709
 710    async def fetch_clan_conversations(
 711        self, clan_id: int, /
 712    ) -> collections.Sequence[clans.ClanConversation]:
 713        """Fetch the conversations/chat channels of the given clan id.
 714
 715        Parameters
 716        ----------
 717        clan_id : `int`
 718            The clan id.
 719
 720        Returns
 721        `collections.Sequence[aiobungie.crates.ClanConversation]`
 722            A sequence of the clan chat channels.
 723        """
 724        resp = await self.rest.fetch_clan_conversations(clan_id)
 725
 726        return self.factory.deserialize_clan_conversations(resp)
 727
 728    async def fetch_clan_admins(
 729        self, clan_id: int, /
 730    ) -> iterators.FlatIterator[clans.ClanMember]:
 731        """Fetch the clan founder and admins.
 732
 733        Parameters
 734        ----------
 735        clan_id : `int`
 736            The clan id.
 737
 738        Returns
 739        -------
 740        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
 741            An iterator over the found clan admins and founder.
 742
 743        Raises
 744        ------
 745        `aiobungie.NotFound`
 746            The requested clan was not found.
 747        """
 748        resp = await self.rest.fetch_clan_admins(clan_id)
 749
 750        return self.factory.deserialize_clan_members(resp)
 751
 752    async def fetch_groups_for_member(
 753        self,
 754        member_id: int,
 755        member_type: typedefs.IntAnd[enums.MembershipType],
 756        /,
 757        *,
 758        filter: int = 0,
 759        group_type: enums.GroupType = enums.GroupType.CLAN,
 760    ) -> collections.Sequence[clans.GroupMember]:
 761        """Fetch information about the groups that a given member has joined.
 762
 763        Parameters
 764        ----------
 765        member_id : `int`
 766            The member's id
 767        member_type : `aiobungie.MembershipType`
 768            The member's membership type.
 769
 770        Other Parameters
 771        ----------------
 772        filter : `int`
 773            Filter apply to list of joined groups. This Default to `0`
 774        group_type : `aiobungie.GroupType`
 775            The group's type.
 776            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 777
 778        Returns
 779        -------
 780        `collections.Sequence[aiobungie.crates.GroupMember]`
 781            A sequence of joined groups for the fetched member.
 782        """
 783        resp = await self.rest.fetch_groups_for_member(
 784            member_id, member_type, filter=filter, group_type=group_type
 785        )
 786
 787        return [
 788            self.factory.deserialize_group_member(group) for group in resp["results"]
 789        ]
 790
 791    async def fetch_potential_groups_for_member(
 792        self,
 793        member_id: int,
 794        member_type: typedefs.IntAnd[enums.MembershipType],
 795        /,
 796        *,
 797        filter: int = 0,
 798        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 799    ) -> collections.Sequence[clans.GroupMember]:
 800        """Fetch the potential groups for a clan member.
 801
 802        Parameters
 803        ----------
 804        member_id : `int`
 805            The member's id
 806        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 807            The member's membership type.
 808
 809        Other Parameters
 810        ----------------
 811        filter : `int`
 812            Filter apply to list of joined groups. This Default to `0`
 813        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
 814            The group's type.
 815            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 816
 817        Returns
 818        -------
 819        `collections.Sequence[aiobungie.crates.GroupMember]`
 820            A sequence of joined potential groups for the fetched member.
 821        """
 822        resp = await self.rest.fetch_potential_groups_for_member(
 823            member_id, member_type, filter=filter, group_type=group_type
 824        )
 825
 826        return [
 827            self.factory.deserialize_group_member(group) for group in resp["results"]
 828        ]
 829
 830    async def fetch_clan_members(
 831        self,
 832        clan_id: int,
 833        /,
 834        *,
 835        name: typing.Optional[str] = None,
 836        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 837    ) -> iterators.FlatIterator[clans.ClanMember]:
 838        """Fetch Bungie clan members.
 839
 840        Parameters
 841        ----------
 842        clan_id : `int`
 843            The clans id
 844
 845        Other Parameters
 846        ----------------
 847        name : `typing.Optional[str]`
 848            If provided, Only players matching this name will be returned.
 849        type : `aiobungie.MembershipType`
 850            An optional clan member's membership type.
 851            This parameter is used to filter the returned results
 852            by the provided membership, For an example XBox memberships only,
 853            Otherwise will return all memberships.
 854
 855        Returns
 856        -------
 857        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
 858            An iterator over the bungie clan members.
 859
 860        Raises
 861        ------
 862        `aiobungie.NotFound`
 863            The clan was not found.
 864        """
 865        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 866
 867        return self.factory.deserialize_clan_members(resp)
 868
 869    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 870        """Fetch the clan banners.
 871
 872        Returns
 873        -------
 874        `collections.Sequence[aiobungie.crates.ClanBanner]`
 875            A sequence of the clan banners.
 876        """
 877        resp = await self.rest.fetch_clan_banners()
 878
 879        return self.factory.deserialize_clan_banners(resp)
 880
 881    # This method is required to be here since it deserialize the clan.
 882    async def kick_clan_member(
 883        self,
 884        access_token: str,
 885        /,
 886        group_id: int,
 887        membership_id: int,
 888        membership_type: typedefs.IntAnd[enums.MembershipType],
 889    ) -> clans.Clan:
 890        """Kick a member from the clan.
 891
 892        .. note::
 893            This request requires OAuth2: oauth2: `AdminGroups` scope.
 894
 895        Parameters
 896        ----------
 897        access_token : `str`
 898            The bearer access token associated with the bungie account.
 899        group_id: `int`
 900            The group id.
 901        membership_id : `int`
 902            The member id to kick.
 903        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 904            The member's membership type.
 905
 906        Returns
 907        -------
 908        `aiobungie.crates.clan.Clan`
 909            The clan that the member was kicked from.
 910        """
 911        resp = await self.rest.kick_clan_member(
 912            access_token,
 913            group_id=group_id,
 914            membership_id=membership_id,
 915            membership_type=membership_type,
 916        )
 917
 918        return self.factory.deserialize_clan(resp)
 919
 920    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 921        """Fetch a Bungie clan's weekly reward state.
 922
 923        Parameters
 924        ----------
 925        clan_id : `int`
 926            The clan's id.
 927
 928        Returns
 929        -------
 930        `aiobungie.crates.Milestone`
 931            A runtime status of the clan's milestone data.
 932        """
 933
 934        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 935
 936        return self.factory.deserialize_milestone(resp)
 937
 938    # * Destiny 2 Entities aka Definitions.
 939
 940    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 941        """Fetch a static inventory item entity given a its hash.
 942
 943        Parameters
 944        ----------
 945        hash: `int`
 946            Inventory item's hash.
 947
 948        Returns
 949        -------
 950        `aiobungie.crates.InventoryEntity`
 951            A bungie inventory item.
 952        """
 953        resp = await self.rest.fetch_inventory_item(hash)
 954
 955        return self.factory.deserialize_inventory_entity(resp)
 956
 957    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 958        """Fetch a Destiny objective entity given a its hash.
 959
 960        Parameters
 961        ----------
 962        hash: `int`
 963            objective's hash.
 964
 965        Returns
 966        -------
 967        `aiobungie.crates.ObjectiveEntity`
 968            An objective entity item.
 969        """
 970        resp = await self.rest.fetch_objective_entity(hash)
 971
 972        return self.factory.deserialize_objective_entity(resp)
 973
 974    async def search_entities(
 975        self, name: str, entity_type: str, *, page: int = 0
 976    ) -> iterators.FlatIterator[entity.SearchableEntity]:
 977        """Search for Destiny2 entities given a name and its type.
 978
 979        Parameters
 980        ----------
 981        name : `str`
 982            The name of the entity, i.e., Thunderlord, One thousand voices.
 983        entity_type : `str`
 984            The type of the entity, AKA Definition,
 985            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 986
 987        Other Parameters
 988        ----------------
 989        page : `int`
 990            An optional page to return. Default to 0.
 991
 992        Returns
 993        -------
 994        `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]`
 995            An iterator over the found results matching the provided name.
 996        """
 997        resp = await self.rest.search_entities(name, entity_type, page=page)
 998
 999        return self.factory.deserialize_inventory_results(resp)
1000
1001    # Fireteams
1002
1003    async def fetch_fireteams(
1004        self,
1005        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1006        *,
1007        platform: typedefs.IntAnd[
1008            fireteams.FireteamPlatform
1009        ] = fireteams.FireteamPlatform.ANY,
1010        language: typing.Union[
1011            fireteams.FireteamLanguage, str
1012        ] = fireteams.FireteamLanguage.ALL,
1013        date_range: int = 0,
1014        page: int = 0,
1015        slots_filter: int = 0,
1016    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1017        """Fetch public Bungie fireteams with open slots.
1018
1019        Parameters
1020        ----------
1021        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1022            The fireteam activity type.
1023
1024        Other Parameters
1025        ----------------
1026        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1027            If this is provided. Then the results will be filtered with the given platform.
1028            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1029        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1030            A locale language to filter the used language in that fireteam.
1031            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1032        date_range : `int`
1033            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1034        page : `int`
1035            The page number. By default its `0` which returns all available activities.
1036        slots_filter : `int`
1037            Filter the returned fireteams based on available slots. Default is `0`
1038
1039        Returns
1040        -------
1041        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1042            A sequence of `aiobungie.crates.Fireteam` or `None`.
1043        """
1044
1045        resp = await self.rest.fetch_fireteams(
1046            activity_type,
1047            platform=platform,
1048            language=language,
1049            date_range=date_range,
1050            page=page,
1051            slots_filter=slots_filter,
1052        )
1053
1054        return self.factory.deserialize_fireteams(resp)
1055
1056    async def fetch_avaliable_clan_fireteams(
1057        self,
1058        access_token: str,
1059        group_id: int,
1060        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1061        *,
1062        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1063        language: typing.Union[fireteams.FireteamLanguage, str],
1064        date_range: int = 0,
1065        page: int = 0,
1066        public_only: bool = False,
1067        slots_filter: int = 0,
1068    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1069        """Fetch a clan's fireteams with open slots.
1070
1071        .. note::
1072            This method requires OAuth2: ReadGroups scope.
1073
1074        Parameters
1075        ----------
1076        access_token : `str`
1077            The bearer access token associated with the bungie account.
1078        group_id : `int`
1079            The group/clan id of the fireteam.
1080        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1081            The fireteam activity type.
1082
1083        Other Parameters
1084        ----------------
1085        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1086            If this is provided. Then the results will be filtered with the given platform.
1087            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1088        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1089            A locale language to filter the used language in that fireteam.
1090            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1091        date_range : `int`
1092            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1093        page : `int`
1094            The page number. By default its `0` which returns all available activities.
1095        public_only: `bool`
1096            If set to True, Then only public fireteams will be returned.
1097        slots_filter : `int`
1098            Filter the returned fireteams based on available slots. Default is `0`
1099
1100        Returns
1101        -------
1102        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1103            A sequence of  fireteams found in the clan.
1104            `None` will be returned if nothing was found.
1105        """
1106        resp = await self.rest.fetch_avaliable_clan_fireteams(
1107            access_token,
1108            group_id,
1109            activity_type,
1110            platform=platform,
1111            language=language,
1112            date_range=date_range,
1113            page=page,
1114            public_only=public_only,
1115            slots_filter=slots_filter,
1116        )
1117
1118        return self.factory.deserialize_fireteams(resp)
1119
1120    async def fetch_clan_fireteam(
1121        self, access_token: str, fireteam_id: int, group_id: int
1122    ) -> fireteams.AvailableFireteam:
1123        """Fetch a specific clan fireteam.
1124
1125        .. note::
1126            This method requires OAuth2: ReadGroups scope.
1127
1128        Parameters
1129        ----------
1130        access_token : `str`
1131            The bearer access token associated with the bungie account.
1132        group_id : `int`
1133            The group/clan id to fetch the fireteam from.
1134        fireteam_id : `int`
1135            The fireteam id to fetch.
1136
1137        Returns
1138        -------
1139        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1140            A sequence of available fireteams objects if exists. else `None` will be returned.
1141        """
1142        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1143
1144        return self.factory.deserialize_available_fireteams(
1145            resp, no_results=True
1146        )  # type: ignore[return-value]
1147
1148    async def fetch_my_clan_fireteams(
1149        self,
1150        access_token: str,
1151        group_id: int,
1152        *,
1153        include_closed: bool = True,
1154        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1155        language: typing.Union[fireteams.FireteamLanguage, str],
1156        filtered: bool = True,
1157        page: int = 0,
1158    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1159        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1160
1161        .. note::
1162            This method requires OAuth2: ReadGroups scope.
1163
1164        Parameters
1165        ----------
1166        access_token : str
1167            The bearer access token associated with the bungie account.
1168        group_id : int
1169            The group/clan id to fetch.
1170
1171        Other Parameters
1172        ----------------
1173        include_closed : bool
1174            If provided and set to True, It will also return closed fireteams.
1175            If provided and set to False, It will only return public fireteams. Default is True.
1176        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1177            If this is provided. Then the results will be filtered with the given platform.
1178            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1179        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1180            A locale language to filter the used language in that fireteam.
1181            Defaults to aiobungie.crates.FireteamLanguage.ALL
1182        filtered : bool
1183            If set to True, it will filter by clan. Otherwise not. Default is True.
1184        page : int
1185            The page number. By default its 0 which returns all available activities.
1186
1187        Returns
1188        -------
1189        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1190            A sequence of available fireteams objects if exists. else `None` will be returned.
1191        """
1192        resp = await self.rest.fetch_my_clan_fireteams(
1193            access_token,
1194            group_id,
1195            include_closed=include_closed,
1196            platform=platform,
1197            language=language,
1198            filtered=filtered,
1199            page=page,
1200        )
1201
1202        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]
1203
1204    # Friends and social.
1205
1206    async def fetch_friends(
1207        self, access_token: str, /
1208    ) -> collections.Sequence[friends.Friend]:
1209        """Fetch bungie friend list.
1210
1211        .. note::
1212            This requests OAuth2: ReadUserData scope.
1213
1214        Parameters
1215        -----------
1216        access_token : `str`
1217            The bearer access token associated with the bungie account.
1218
1219        Returns
1220        -------
1221        `collections.Sequence[aiobungie.crates.Friend]`
1222            A sequence of the friends associated with that access token.
1223        """
1224
1225        resp = await self.rest.fetch_friends(access_token)
1226
1227        return self.factory.deserialize_friends(resp)
1228
1229    async def fetch_friend_requests(
1230        self, access_token: str, /
1231    ) -> friends.FriendRequestView:
1232        """Fetch pending bungie friend requests queue.
1233
1234        .. note::
1235            This requests OAuth2: ReadUserData scope.
1236
1237        Parameters
1238        -----------
1239        access_token : `str`
1240            The bearer access token associated with the bungie account.
1241
1242        Returns
1243        -------
1244        `aiobungie.crates.FriendRequestView`
1245            A friend requests view of that associated access token.
1246        """
1247
1248        resp = await self.rest.fetch_friend_requests(access_token)
1249
1250        return self.factory.deserialize_friend_requests(resp)
1251
1252    # Applications and Developer portal.
1253
1254    async def fetch_application(self, appid: int, /) -> application.Application:
1255        """Fetch a Bungie application.
1256
1257        Parameters
1258        -----------
1259        appid: `int`
1260            The application id.
1261
1262        Returns
1263        --------
1264        `aiobungie.crates.Application`
1265            A Bungie application.
1266        """
1267        resp = await self.rest.fetch_application(appid)
1268
1269        return self.factory.deserialize_app(resp)
1270
1271    # Milestones
1272
1273    async def fetch_public_milestone_content(
1274        self, milestone_hash: int, /
1275    ) -> milestones.MilestoneContent:
1276        """Fetch the milestone content given its hash.
1277
1278        Parameters
1279        ----------
1280        milestone_hash : `int`
1281            The milestone hash.
1282
1283        Returns
1284        -------
1285        `aiobungie.crates.milestones.MilestoneContent`
1286            A milestone content object.
1287        """
1288        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1289
1290        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client application.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

A aiobungie.RESTClient REST client can also be used alone for low-level concepts.

Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
Example
TOKEN = "SOME_TOKEN"
async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client:
    client = aiobungie.Client(TOKEN, rest_client=rest_client)

max_retries : int The max retries number to retry if the request hit a 5xx status code. max_ratelimit_retries : int The max retries number to retry if the request hit a 429 status code. Defaults to 3. client_secret : str | None An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. client_id : int | None An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.

Client( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, rest_client: Optional[aiobungie.interfaces.rest.RESTInterface] = None, max_retries: int = 4, max_ratelimit_retries: int = 3)
102    def __init__(
103        self,
104        token: str,
105        /,
106        client_secret: typing.Optional[str] = None,
107        client_id: typing.Optional[int] = None,
108        *,
109        rest_client: typing.Optional[interfaces.RESTInterface] = None,
110        max_retries: int = 4,
111        max_ratelimit_retries: int = 3,
112    ) -> None:
113
114        self._client_secret = client_secret
115        self._client_id = client_id
116
117        self._rest = (
118            rest_client
119            if rest_client is not None
120            else rest_.RESTClient(
121                token,
122                client_secret,
123                client_id,
124                max_retries=max_retries,
125                max_ratelimit_retries=max_ratelimit_retries,
126            )
127        )
128
129        self._factory = factory_.Factory(self)

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface

Returns the REST client for the this client.

request: aiobungie.Client

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

def run( self, future: collections.abc.Coroutine[typing.Any, None, None], debug: bool = False) -> None:
147    def run(
148        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
149    ) -> None:
150        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
151        try:
152            if not loop.is_running():
153                loop.set_debug(debug)
154                loop.run_until_complete(future)
155
156        except Exception as exc:
157            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
158
159        except KeyboardInterrupt:
160            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
161            return
162
163        finally:
164            if self._rest.is_alive:
165                # Clean up sessions.
166                loop.run_until_complete(self._rest.close())

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • future (collections.Coroutine[None, None, None]): A coroutine object.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
170    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
171        """Fetch and return a user object of the bungie net user associated with account.
172
173        .. warning::
174            This method requires OAuth2 scope and a Bearer access token.
175
176        Parameters
177        ----------
178        access_token : `str`
179            A valid Bearer access token for the authorization.
180
181        Returns
182        -------
183        `aiobungie.crates.user.User`
184            A user object includes the Destiny memberships and Bungie.net user.
185        """
186        resp = await self.rest.fetch_current_user_memberships(access_token)
187
188        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
190    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
191        """Fetch a Bungie user by their BungieNet id.
192
193        .. note::
194            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
195            for other memberships.
196
197        Parameters
198        ----------
199        id: `int`
200            The user id.
201
202        Returns
203        -------
204        `aiobungie.crates.user.BungieUser`
205            A Bungie user.
206
207        Raises
208        ------
209        `aiobungie.error.NotFound`
210            The user was not found.
211        """
212        payload = await self.rest.fetch_bungie_user(id)
213
214        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> aiobungie.FlatIterator[aiobungie.crates.user.SearchableDestinyUser]:
216    async def search_users(
217        self, name: str, /
218    ) -> iterators.FlatIterator[user.SearchableDestinyUser]:
219        """Search for players and return all players that matches the same name.
220
221        Parameters
222        ----------
223        name : `buildins.str`
224            The user name.
225
226        Returns
227        -------
228        `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]`
229            A sequence of destiny memberships.
230        """
231        payload = await self.rest.search_users(name)
232
233        return iterators.FlatIterator(
234            [
235                self.factory.deserialize_searched_user(user)
236                for user in payload["searchResults"]
237            ]
238        )

Search for players and return all players that matches the same name.

Parameters
  • name (buildins.str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
240    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
241        """Fetch all available user themes.
242
243        Returns
244        -------
245        `collections.Sequence[aiobungie.crates.user.UserThemes]`
246            A sequence of user themes.
247        """
248        data = await self.rest.fetch_user_themes()
249
250        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
252    async def fetch_hard_types(
253        self,
254        credential: int,
255        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
256        /,
257    ) -> user.HardLinkedMembership:
258        """Gets any hard linked membership given a credential.
259        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
260        Cross Save aware.
261
262        Parameters
263        ----------
264        credential: `int`
265            A valid SteamID64
266        type: `aiobungie.CredentialType`
267            The credential type. This must not be changed
268            Since its only credential that works "currently"
269
270        Returns
271        -------
272        `aiobungie.crates.user.HardLinkedMembership`
273            Information about the hard linked data.
274        """
275
276        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
277
278        return user.HardLinkedMembership(
279            id=int(payload["membershipId"]),
280            type=enums.MembershipType(payload["membershipType"]),
281            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
282        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
284    async def fetch_membership_from_id(
285        self,
286        id: int,
287        /,
288        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
289    ) -> user.User:
290        """Fetch Bungie user's memberships from their id.
291
292        Notes
293        -----
294        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
295        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
296        see `aiobungie.crates.user.DestinyMembership` for more details.
297        * If you only want the bungie user. Consider using `Client.fetch_user` method.
298
299        Parameters
300        ----------
301        id : `int`
302            The user's id.
303        type : `aiobungie.MembershipType`
304            The user's membership type.
305
306        Returns
307        -------
308        `aiobungie.crates.User`
309            A Bungie user with their membership types.
310
311        Raises
312        ------
313        aiobungie.NotFound
314            The requested user was not found.
315        """
316        payload = await self.rest.fetch_membership_from_id(id, type)
317
318        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
320    async def fetch_user_credentials(
321        self, access_token: str, membership_id: int, /
322    ) -> collections.Sequence[user.UserCredentials]:
323        """Fetch an array of credential types attached to the requested account.
324
325        .. note::
326            This method require OAuth2 Bearer access token.
327
328        Parameters
329        ----------
330        access_token : `str`
331            The bearer access token associated with the bungie account.
332        membership_id : `int`
333            The id of the membership to return.
334
335        Returns
336        -------
337        `collections.Sequence[aiobungie.crates.UserCredentials]`
338            A sequence of the attached user credentials.
339
340        Raises
341        ------
342        `aiobungie.Unauthorized`
343            The access token was wrong or no access token passed.
344        """
345        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
346
347        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.Component:
351    async def fetch_profile(
352        self,
353        member_id: int,
354        type: typedefs.IntAnd[enums.MembershipType],
355        components: list[enums.ComponentType],
356        auth: typing.Optional[str] = None,
357    ) -> components.Component:
358        """
359        Fetch a bungie profile passing components to the request.
360
361        Parameters
362        ----------
363        member_id: `int`
364            The member's id.
365        type: `aiobungie.MembershipType`
366            A valid membership type.
367        components : `list[aiobungie.ComponentType]`
368            List of profile components to collect and return.
369
370        Other Parameters
371        ----------------
372        auth : `typing.Optional[str]`
373            A Bearer access_token to make the request with.
374            This is optional and limited to components that only requires an Authorization token.
375
376        Returns
377        --------
378        `aiobungie.crates.Component`
379            A Destiny 2 player profile with its components.
380            Only passed components will be available if they exists. Otherwise they will be `None`
381
382        Raises
383        ------
384        `aiobungie.MembershipTypeError`
385            The provided membership type was invalid.
386        """
387        data = await self.rest.fetch_profile(member_id, type, components, auth)
388        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
390    async def fetch_linked_profiles(
391        self,
392        member_id: int,
393        member_type: typedefs.IntAnd[enums.MembershipType],
394        /,
395        *,
396        all: bool = False,
397    ) -> profile.LinkedProfile:
398        """Returns a summary information about all profiles linked to the requested member.
399
400        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
401
402        .. note::
403            It will only return linked accounts whose linkages you are allowed to view.
404
405        Parameters
406        ----------
407        member_id : `int`
408            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
409        member_type : `aiobungie.MembershipType`
410            The type for the membership whose linked Destiny account you want to return.
411
412        Other Parameters
413        ----------------
414        all : `bool`
415            If provided and set to `True`, All memberships regardless
416            of whether they're obscured by overrides will be returned,
417
418            If provided and set to `False`, Only available memberships will be returned.
419            The default for this is `False`.
420
421        Returns
422        -------
423        `aiobungie.crates.profile.LinkedProfile`
424            A linked profile object.
425        """
426        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
427
428        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_player( self, name: str, code: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
430    async def fetch_player(
431        self,
432        name: str,
433        code: int,
434        /,
435        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
436    ) -> collections.Sequence[user.DestinyMembership]:
437        """Fetch a Destiny 2 player's memberships.
438
439        Parameters
440        -----------
441        name: `str`
442            The unique Bungie player name.
443        code : `int`
444            The unique Bungie display name code.
445        type: `aiobungie.internal.enums.MembershipType`
446            The player's membership type, e,g. XBOX, STEAM, PSN
447
448        Returns
449        --------
450        `collections.Sequence[aiobungie.crates.DestinyMembership]`
451            A sequence of the found Destiny 2 player memberships.
452            An empty sequence will be returned if no one found.
453
454        Raises
455        ------
456        `aiobungie.MembershipTypeError`
457            The provided membership type was invalid.
458        """
459        resp = await self.rest.fetch_player(name, code, type)
460
461        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.CharacterComponent:
463    async def fetch_character(
464        self,
465        member_id: int,
466        membership_type: typedefs.IntAnd[enums.MembershipType],
467        character_id: int,
468        components: list[enums.ComponentType],
469        auth: typing.Optional[str] = None,
470    ) -> components.CharacterComponent:
471        """Fetch a Destiny 2 character.
472
473        Parameters
474        ----------
475        member_id: `int`
476            A valid bungie member id.
477        character_id: `int`
478            The Destiny character id to retrieve.
479        membership_type: `aiobungie.internal.enums.MembershipType`
480            The member's membership type.
481        components: `list[aiobungie.ComponentType]`
482            Multiple arguments of character components to collect and return.
483
484        Other Parameters
485        ----------------
486        auth : `typing.Optional[str]`
487            A Bearer access_token to make the request with.
488            This is optional and limited to components that only requires an Authorization token.
489
490        Returns
491        -------
492        `aiobungie.crates.CharacterComponent`
493            A Bungie character component.
494
495        `aiobungie.MembershipTypeError`
496            The provided membership type was invalid.
497        """
498        resp = await self.rest.fetch_character(
499            member_id, membership_type, character_id, components, auth
500        )
501
502        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (aiobungie.MembershipType): The member's membership type.
  • components (list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
504    async def fetch_unique_weapon_history(
505        self,
506        membership_id: int,
507        character_id: int,
508        membership_type: typedefs.IntAnd[enums.MembershipType],
509    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
510        """Fetch details about unique weapon usage for a character. Includes all exotics.
511
512        Parameters
513        ----------
514        membership_id : `int`
515            The Destiny user membership id.
516        character_id : `int`
517            The character id to retrieve.
518        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
519            The Destiny user's membership type.
520
521        Returns
522        -------
523        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
524            A sequence of the weapon's extended values.
525        """
526        resp = await self._rest.fetch_unique_weapon_history(
527            membership_id, character_id, membership_type
528        )
529
530        return [
531            self._factory.deserialize_extended_weapon_values(weapon)
532            for weapon in resp["weapons"]
533        ]

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], *, membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> aiobungie.FlatIterator[aiobungie.crates.activity.Activity]:
537    async def fetch_activities(
538        self,
539        member_id: int,
540        character_id: int,
541        mode: typedefs.IntAnd[enums.GameMode],
542        *,
543        membership_type: typedefs.IntAnd[
544            enums.MembershipType
545        ] = enums.MembershipType.ALL,
546        page: int = 0,
547        limit: int = 250,
548    ) -> iterators.FlatIterator[activity.Activity]:
549        """Fetch a Destiny 2 activity for the specified character id.
550
551        Parameters
552        ----------
553        member_id: `int`
554            The user id that starts with `4611`.
555        character_id: `int`
556            The id of the character to retrieve the activities for.
557        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
558            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
559
560        Other Parameters
561        ----------------
562        membership_type: `aiobungie.internal.enums.MembershipType`
563            The Member ship type, if nothing was passed than it will return all.
564        page: int
565            The page number. Default is `0`
566        limit: int
567            Limit the returned result. Default is `250`.
568
569        Returns
570        -------
571        `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]`
572            An iterator of the player's activities.
573
574        Raises
575        ------
576        `aiobungie.MembershipTypeError`
577            The provided membership type was invalid.
578        """
579        resp = await self.rest.fetch_activities(
580            member_id,
581            character_id,
582            mode,
583            membership_type=membership_type,
584            page=page,
585            limit=limit,
586        )
587
588        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
590    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
591        """Fetch a post activity details.
592
593        Parameters
594        ----------
595        instance_id: `int`
596            The activity instance id.
597
598        Returns
599        -------
600        `aiobungie.crates.PostActivity`
601           A post activity object.
602        """
603        resp = await self.rest.fetch_post_activity(instance_id)
604
605        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.FlatIterator[aiobungie.crates.activity.AggregatedActivity]:
607    async def fetch_aggregated_activity_stats(
608        self,
609        character_id: int,
610        membership_id: int,
611        membership_type: typedefs.IntAnd[enums.MembershipType],
612    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
613        """Fetch aggregated activity stats for a character.
614
615        Parameters
616        ----------
617        character_id: `int`
618            The id of the character to retrieve the activities for.
619        membership_id: `int`
620            The id of the user that started with `4611`.
621        membership_type: `aiobungie.internal.enums.MembershipType`
622            The Member ship type.
623
624        Returns
625        -------
626        `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]`
627            An iterator of the player's activities.
628
629        Raises
630        ------
631        `aiobungie.MembershipTypeError`
632            The provided membership type was invalid.
633        """
634        resp = await self.rest.fetch_aggregated_activity_stats(
635            character_id, membership_id, membership_type
636        )
637
638        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (aiobungie.MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> aiobungie.crates.clans.Clan:
642    async def fetch_clan_from_id(
643        self,
644        id: int,
645        /,
646        access_token: typing.Optional[str] = None,
647    ) -> clans.Clan:
648        """Fetch a Bungie Clan by its id.
649
650        Parameters
651        -----------
652        id: `int`
653            The clan id.
654
655        Returns
656        --------
657        `aiobungie.crates.Clan`
658            An Bungie clan.
659
660        Raises
661        ------
662        `aiobungie.NotFound`
663            The clan was not found.
664        """
665        resp = await self.rest.fetch_clan_from_id(id, access_token)
666
667        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
669    async def fetch_clan(
670        self,
671        name: str,
672        /,
673        access_token: typing.Optional[str] = None,
674        *,
675        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
676    ) -> clans.Clan:
677        """Fetch a Clan by its name.
678        This method will return the first clan found with given name.
679
680        Parameters
681        ----------
682        name: `str`
683            The clan name
684
685        Other Parameters
686        ----------------
687        access_token : `typing.Optional[str]`
688            An optional access token to make the request with.
689
690            If the token was bound to a member of the clan,
691            This field `aiobungie.crates.Clan.current_user_membership` will be available
692            and will return the membership of the user who made this request.
693        type : `aiobungie.GroupType`
694            The group type, Default is aiobungie.GroupType.CLAN.
695
696        Returns
697        -------
698        `aiobungie.crates.Clan`
699            A Bungie clan.
700
701        Raises
702        ------
703        `aiobungie.NotFound`
704            The clan was not found.
705        """
706        resp = await self.rest.fetch_clan(name, access_token, type=type)
707
708        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
710    async def fetch_clan_conversations(
711        self, clan_id: int, /
712    ) -> collections.Sequence[clans.ClanConversation]:
713        """Fetch the conversations/chat channels of the given clan id.
714
715        Parameters
716        ----------
717        clan_id : `int`
718            The clan id.
719
720        Returns
721        `collections.Sequence[aiobungie.crates.ClanConversation]`
722            A sequence of the clan chat channels.
723        """
724        resp = await self.rest.fetch_clan_conversations(clan_id)
725
726        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
728    async def fetch_clan_admins(
729        self, clan_id: int, /
730    ) -> iterators.FlatIterator[clans.ClanMember]:
731        """Fetch the clan founder and admins.
732
733        Parameters
734        ----------
735        clan_id : `int`
736            The clan id.
737
738        Returns
739        -------
740        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
741            An iterator over the found clan admins and founder.
742
743        Raises
744        ------
745        `aiobungie.NotFound`
746            The requested clan was not found.
747        """
748        resp = await self.rest.fetch_clan_admins(clan_id)
749
750        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: aiobungie.GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
752    async def fetch_groups_for_member(
753        self,
754        member_id: int,
755        member_type: typedefs.IntAnd[enums.MembershipType],
756        /,
757        *,
758        filter: int = 0,
759        group_type: enums.GroupType = enums.GroupType.CLAN,
760    ) -> collections.Sequence[clans.GroupMember]:
761        """Fetch information about the groups that a given member has joined.
762
763        Parameters
764        ----------
765        member_id : `int`
766            The member's id
767        member_type : `aiobungie.MembershipType`
768            The member's membership type.
769
770        Other Parameters
771        ----------------
772        filter : `int`
773            Filter apply to list of joined groups. This Default to `0`
774        group_type : `aiobungie.GroupType`
775            The group's type.
776            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
777
778        Returns
779        -------
780        `collections.Sequence[aiobungie.crates.GroupMember]`
781            A sequence of joined groups for the fetched member.
782        """
783        resp = await self.rest.fetch_groups_for_member(
784            member_id, member_type, filter=filter, group_type=group_type
785        )
786
787        return [
788            self.factory.deserialize_group_member(group) for group in resp["results"]
789        ]

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
791    async def fetch_potential_groups_for_member(
792        self,
793        member_id: int,
794        member_type: typedefs.IntAnd[enums.MembershipType],
795        /,
796        *,
797        filter: int = 0,
798        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
799    ) -> collections.Sequence[clans.GroupMember]:
800        """Fetch the potential groups for a clan member.
801
802        Parameters
803        ----------
804        member_id : `int`
805            The member's id
806        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
807            The member's membership type.
808
809        Other Parameters
810        ----------------
811        filter : `int`
812            Filter apply to list of joined groups. This Default to `0`
813        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
814            The group's type.
815            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
816
817        Returns
818        -------
819        `collections.Sequence[aiobungie.crates.GroupMember]`
820            A sequence of joined potential groups for the fetched member.
821        """
822        resp = await self.rest.fetch_potential_groups_for_member(
823            member_id, member_type, filter=filter, group_type=group_type
824        )
825
826        return [
827            self.factory.deserialize_group_member(group) for group in resp["results"]
828        ]

Fetch the potential groups for a clan member.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
830    async def fetch_clan_members(
831        self,
832        clan_id: int,
833        /,
834        *,
835        name: typing.Optional[str] = None,
836        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
837    ) -> iterators.FlatIterator[clans.ClanMember]:
838        """Fetch Bungie clan members.
839
840        Parameters
841        ----------
842        clan_id : `int`
843            The clans id
844
845        Other Parameters
846        ----------------
847        name : `typing.Optional[str]`
848            If provided, Only players matching this name will be returned.
849        type : `aiobungie.MembershipType`
850            An optional clan member's membership type.
851            This parameter is used to filter the returned results
852            by the provided membership, For an example XBox memberships only,
853            Otherwise will return all memberships.
854
855        Returns
856        -------
857        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
858            An iterator over the bungie clan members.
859
860        Raises
861        ------
862        `aiobungie.NotFound`
863            The clan was not found.
864        """
865        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
866
867        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (typing.Optional[str]): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
869    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
870        """Fetch the clan banners.
871
872        Returns
873        -------
874        `collections.Sequence[aiobungie.crates.ClanBanner]`
875            A sequence of the clan banners.
876        """
877        resp = await self.rest.fetch_clan_banners()
878
879        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.crates.clans.Clan:
882    async def kick_clan_member(
883        self,
884        access_token: str,
885        /,
886        group_id: int,
887        membership_id: int,
888        membership_type: typedefs.IntAnd[enums.MembershipType],
889    ) -> clans.Clan:
890        """Kick a member from the clan.
891
892        .. note::
893            This request requires OAuth2: oauth2: `AdminGroups` scope.
894
895        Parameters
896        ----------
897        access_token : `str`
898            The bearer access token associated with the bungie account.
899        group_id: `int`
900            The group id.
901        membership_id : `int`
902            The member id to kick.
903        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
904            The member's membership type.
905
906        Returns
907        -------
908        `aiobungie.crates.clan.Clan`
909            The clan that the member was kicked from.
910        """
911        resp = await self.rest.kick_clan_member(
912            access_token,
913            group_id=group_id,
914            membership_id=membership_id,
915            membership_type=membership_type,
916        )
917
918        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
920    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
921        """Fetch a Bungie clan's weekly reward state.
922
923        Parameters
924        ----------
925        clan_id : `int`
926            The clan's id.
927
928        Returns
929        -------
930        `aiobungie.crates.Milestone`
931            A runtime status of the clan's milestone data.
932        """
933
934        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
935
936        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
940    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
941        """Fetch a static inventory item entity given a its hash.
942
943        Parameters
944        ----------
945        hash: `int`
946            Inventory item's hash.
947
948        Returns
949        -------
950        `aiobungie.crates.InventoryEntity`
951            A bungie inventory item.
952        """
953        resp = await self.rest.fetch_inventory_item(hash)
954
955        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
957    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
958        """Fetch a Destiny objective entity given a its hash.
959
960        Parameters
961        ----------
962        hash: `int`
963            objective's hash.
964
965        Returns
966        -------
967        `aiobungie.crates.ObjectiveEntity`
968            An objective entity item.
969        """
970        resp = await self.rest.fetch_objective_entity(hash)
971
972        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> aiobungie.FlatIterator[aiobungie.crates.entity.SearchableEntity]:
974    async def search_entities(
975        self, name: str, entity_type: str, *, page: int = 0
976    ) -> iterators.FlatIterator[entity.SearchableEntity]:
977        """Search for Destiny2 entities given a name and its type.
978
979        Parameters
980        ----------
981        name : `str`
982            The name of the entity, i.e., Thunderlord, One thousand voices.
983        entity_type : `str`
984            The type of the entity, AKA Definition,
985            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
986
987        Other Parameters
988        ----------------
989        page : `int`
990            An optional page to return. Default to 0.
991
992        Returns
993        -------
994        `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]`
995            An iterator over the found results matching the provided name.
996        """
997        resp = await self.rest.search_entities(name, entity_type, page=page)
998
999        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1003    async def fetch_fireteams(
1004        self,
1005        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1006        *,
1007        platform: typedefs.IntAnd[
1008            fireteams.FireteamPlatform
1009        ] = fireteams.FireteamPlatform.ANY,
1010        language: typing.Union[
1011            fireteams.FireteamLanguage, str
1012        ] = fireteams.FireteamLanguage.ALL,
1013        date_range: int = 0,
1014        page: int = 0,
1015        slots_filter: int = 0,
1016    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1017        """Fetch public Bungie fireteams with open slots.
1018
1019        Parameters
1020        ----------
1021        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1022            The fireteam activity type.
1023
1024        Other Parameters
1025        ----------------
1026        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1027            If this is provided. Then the results will be filtered with the given platform.
1028            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1029        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1030            A locale language to filter the used language in that fireteam.
1031            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1032        date_range : `int`
1033            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1034        page : `int`
1035            The page number. By default its `0` which returns all available activities.
1036        slots_filter : `int`
1037            Filter the returned fireteams based on available slots. Default is `0`
1038
1039        Returns
1040        -------
1041        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1042            A sequence of `aiobungie.crates.Fireteam` or `None`.
1043        """
1044
1045        resp = await self.rest.fetch_fireteams(
1046            activity_type,
1047            platform=platform,
1048            language=language,
1049            date_range=date_range,
1050            page=page,
1051            slots_filter=slots_filter,
1052        )
1053
1054        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1056    async def fetch_avaliable_clan_fireteams(
1057        self,
1058        access_token: str,
1059        group_id: int,
1060        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1061        *,
1062        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1063        language: typing.Union[fireteams.FireteamLanguage, str],
1064        date_range: int = 0,
1065        page: int = 0,
1066        public_only: bool = False,
1067        slots_filter: int = 0,
1068    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1069        """Fetch a clan's fireteams with open slots.
1070
1071        .. note::
1072            This method requires OAuth2: ReadGroups scope.
1073
1074        Parameters
1075        ----------
1076        access_token : `str`
1077            The bearer access token associated with the bungie account.
1078        group_id : `int`
1079            The group/clan id of the fireteam.
1080        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1081            The fireteam activity type.
1082
1083        Other Parameters
1084        ----------------
1085        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1086            If this is provided. Then the results will be filtered with the given platform.
1087            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1088        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1089            A locale language to filter the used language in that fireteam.
1090            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1091        date_range : `int`
1092            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1093        page : `int`
1094            The page number. By default its `0` which returns all available activities.
1095        public_only: `bool`
1096            If set to True, Then only public fireteams will be returned.
1097        slots_filter : `int`
1098            Filter the returned fireteams based on available slots. Default is `0`
1099
1100        Returns
1101        -------
1102        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1103            A sequence of  fireteams found in the clan.
1104            `None` will be returned if nothing was found.
1105        """
1106        resp = await self.rest.fetch_avaliable_clan_fireteams(
1107            access_token,
1108            group_id,
1109            activity_type,
1110            platform=platform,
1111            language=language,
1112            date_range=date_range,
1113            page=page,
1114            public_only=public_only,
1115            slots_filter=slots_filter,
1116        )
1117
1118        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1120    async def fetch_clan_fireteam(
1121        self, access_token: str, fireteam_id: int, group_id: int
1122    ) -> fireteams.AvailableFireteam:
1123        """Fetch a specific clan fireteam.
1124
1125        .. note::
1126            This method requires OAuth2: ReadGroups scope.
1127
1128        Parameters
1129        ----------
1130        access_token : `str`
1131            The bearer access token associated with the bungie account.
1132        group_id : `int`
1133            The group/clan id to fetch the fireteam from.
1134        fireteam_id : `int`
1135            The fireteam id to fetch.
1136
1137        Returns
1138        -------
1139        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1140            A sequence of available fireteams objects if exists. else `None` will be returned.
1141        """
1142        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1143
1144        return self.factory.deserialize_available_fireteams(
1145            resp, no_results=True
1146        )  # type: ignore[return-value]

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1148    async def fetch_my_clan_fireteams(
1149        self,
1150        access_token: str,
1151        group_id: int,
1152        *,
1153        include_closed: bool = True,
1154        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1155        language: typing.Union[fireteams.FireteamLanguage, str],
1156        filtered: bool = True,
1157        page: int = 0,
1158    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1159        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1160
1161        .. note::
1162            This method requires OAuth2: ReadGroups scope.
1163
1164        Parameters
1165        ----------
1166        access_token : str
1167            The bearer access token associated with the bungie account.
1168        group_id : int
1169            The group/clan id to fetch.
1170
1171        Other Parameters
1172        ----------------
1173        include_closed : bool
1174            If provided and set to True, It will also return closed fireteams.
1175            If provided and set to False, It will only return public fireteams. Default is True.
1176        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1177            If this is provided. Then the results will be filtered with the given platform.
1178            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1179        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1180            A locale language to filter the used language in that fireteam.
1181            Defaults to aiobungie.crates.FireteamLanguage.ALL
1182        filtered : bool
1183            If set to True, it will filter by clan. Otherwise not. Default is True.
1184        page : int
1185            The page number. By default its 0 which returns all available activities.
1186
1187        Returns
1188        -------
1189        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1190            A sequence of available fireteams objects if exists. else `None` will be returned.
1191        """
1192        resp = await self.rest.fetch_my_clan_fireteams(
1193            access_token,
1194            group_id,
1195            include_closed=include_closed,
1196            platform=platform,
1197            language=language,
1198            filtered=filtered,
1199            page=page,
1200        )
1201
1202        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1206    async def fetch_friends(
1207        self, access_token: str, /
1208    ) -> collections.Sequence[friends.Friend]:
1209        """Fetch bungie friend list.
1210
1211        .. note::
1212            This requests OAuth2: ReadUserData scope.
1213
1214        Parameters
1215        -----------
1216        access_token : `str`
1217            The bearer access token associated with the bungie account.
1218
1219        Returns
1220        -------
1221        `collections.Sequence[aiobungie.crates.Friend]`
1222            A sequence of the friends associated with that access token.
1223        """
1224
1225        resp = await self.rest.fetch_friends(access_token)
1226
1227        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1229    async def fetch_friend_requests(
1230        self, access_token: str, /
1231    ) -> friends.FriendRequestView:
1232        """Fetch pending bungie friend requests queue.
1233
1234        .. note::
1235            This requests OAuth2: ReadUserData scope.
1236
1237        Parameters
1238        -----------
1239        access_token : `str`
1240            The bearer access token associated with the bungie account.
1241
1242        Returns
1243        -------
1244        `aiobungie.crates.FriendRequestView`
1245            A friend requests view of that associated access token.
1246        """
1247
1248        resp = await self.rest.fetch_friend_requests(access_token)
1249
1250        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1254    async def fetch_application(self, appid: int, /) -> application.Application:
1255        """Fetch a Bungie application.
1256
1257        Parameters
1258        -----------
1259        appid: `int`
1260            The application id.
1261
1262        Returns
1263        --------
1264        `aiobungie.crates.Application`
1265            A Bungie application.
1266        """
1267        resp = await self.rest.fetch_application(appid)
1268
1269        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1273    async def fetch_public_milestone_content(
1274        self, milestone_hash: int, /
1275    ) -> milestones.MilestoneContent:
1276        """Fetch the milestone content given its hash.
1277
1278        Parameters
1279        ----------
1280        milestone_hash : `int`
1281            The milestone hash.
1282
1283        Returns
1284        -------
1285        `aiobungie.crates.milestones.MilestoneContent`
1286            A milestone content object.
1287        """
1288        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1289
1290        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
782@typing.final
783class ClosedReasons(Flag):
784    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
785
786    NONE = 0
787    MATCHMAKING = 1
788    LOADING = 2
789    SOLO = 4
790    """The activity is required to be played solo."""
791    INTERNAL_REASONS = 8
792    """
793    The user can't be joined for one of a variety of internal reasons.
794    Basically, the game can't let you join at this time,
795    but for reasons that aren't under the control of this user
796    """
797    DISALLOWED_BY_GAME_STATE = 16
798    """The user's current activity/quest/other transitory game state is preventing joining."""
799    OFFLINE = 32768
800    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: <enum 'ComponentPrivacy'>>
DISABLED = <ComponentFields.DISABLED: False>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
363@typing.final
364class ComponentType(Enum):
365    """An Enum for Destiny 2 profile Components."""
366
367    NONE = 0
368
369    PROFILE = 100
370    PROFILE_INVENTORIES = 102
371    PROFILE_CURRENCIES = 103
372    PROFILE_PROGRESSION = 104
373    ALL_PROFILES = (
374        PROFILE,
375        PROFILE_INVENTORIES,
376        PROFILE_CURRENCIES,
377        PROFILE_PROGRESSION,
378    )
379    """All profile components."""
380
381    VENDORS = 400
382    VENDOR_SALES = 402
383    VENDOR_RECEIPTS = 101
384    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
385    """All vendor components."""
386
387    # Items
388    ITEM_INSTANCES = 300
389    ITEM_OBJECTIVES = 301
390    ITEM_PERKS = 302
391    ITEM_RENDER_DATA = 303
392    ITEM_STATS = 304
393    ITEM_SOCKETS = 305
394    ITEM_TALENT_GRINDS = 306
395    ITEM_PLUG_STATES = 308
396    ITEM_PLUG_OBJECTIVES = 309
397    ITEM_REUSABLE_PLUGS = 310
398
399    ALL_ITEMS = (
400        ITEM_PLUG_OBJECTIVES,
401        ITEM_PLUG_STATES,
402        ITEM_SOCKETS,
403        ITEM_INSTANCES,
404        ITEM_OBJECTIVES,
405        ITEM_PERKS,
406        ITEM_RENDER_DATA,
407        ITEM_STATS,
408        ITEM_TALENT_GRINDS,
409        ITEM_REUSABLE_PLUGS,
410    )
411    """All item components."""
412
413    PLATFORM_SILVER = 105
414    KIOSKS = 500
415    CURRENCY_LOOKUPS = 600
416    PRESENTATION_NODES = 700
417    COLLECTIBLES = 800
418    RECORDS = 900
419    TRANSITORY = 1000
420    METRICS = 1100
421    INVENTORIES = 102
422    STRING_VARIABLES = 1200
423    CRAFTABLES = 1300
424
425    CHARACTERS = 200
426    CHARACTER_INVENTORY = 201
427    CHARECTER_PROGRESSION = 202
428    CHARACTER_RENDER_DATA = 203
429    CHARACTER_ACTIVITIES = 204
430    CHARACTER_EQUIPMENT = 205
431
432    ALL_CHARACTERS = (
433        CHARACTERS,
434        CHARACTER_INVENTORY,
435        CHARECTER_PROGRESSION,
436        CHARACTER_RENDER_DATA,
437        CHARACTER_ACTIVITIES,
438        CHARACTER_EQUIPMENT,
439        RECORDS,
440    )
441    """All character components."""
442
443    ALL = (
444        *ALL_PROFILES,  # type: ignore
445        *ALL_CHARACTERS,  # type: ignore
446        *ALL_VENDORS,  # type: ignore
447        *ALL_ITEMS,  # type: ignore
448        RECORDS,
449        CURRENCY_LOOKUPS,
450        PRESENTATION_NODES,
451        COLLECTIBLES,
452        KIOSKS,
453        METRICS,
454        PLATFORM_SILVER,
455        INVENTORIES,
456        STRING_VARIABLES,
457        TRANSITORY,
458        CRAFTABLES,
459    )
460    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
664@typing.final
665class CredentialType(int, Enum):
666    """The types of the accounts system supports at bungie."""
667
668    NONE = 0
669    XUID = 1
670    PSNID = 2
671    WILD = 3
672    FAKE = 4
673    FACEBOOK = 5
674    GOOGLE = 8
675    WINDOWS = 9
676    DEMONID = 10
677    STEAMID = 12
678    BATTLENETID = 14
679    STADIAID = 16
680    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
542@typing.final
543class DamageType(int, Enum):
544    """Enums for Destiny Damage types"""
545
546    NONE = 0
547    KINETIC = 1
548    ARC = 2
549    SOLAR = 3
550    VOID = 4
551    RAID = 5
552    """This is a special damage type reserved for some raid activity encounters."""
553    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
65@typing.final
66class Difficulty(int, enums.Enum):
67    """An enum for activities difficulties."""
68
69    TRIVIAL = 0
70    EASY = 1
71    NORMAL = 2
72    CHALLENGING = 3
73    HARD = 4
74    BRAVE = 5
75    ALMOST_IMPOSSIBLE = 6
76    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
165@typing.final
166class Dungeon(int, Enum):
167    """An Enum for all available Dungeon/Like missions in Destiny 2."""
168
169    NORMAL_PRESAGE = 2124066889
170    """Normal Presage"""
171
172    MASTER_PRESAGE = 4212753278
173    """Master Presage"""
174
175    HARBINGER = 1738383283
176    """Harbinger"""
177
178    PROPHECY = 4148187374
179    """Prophecy"""
180
181    MASTER_POH = 785700673
182    """Master Pit of Heresy?"""
183
184    LEGEND_POH = 785700678
185    """Legend Pit of Heresy?"""
186
187    POH = 1375089621
188    """Normal Pit of Heresy."""
189
190    SHATTERED = 2032534090
191    """Shattered Throne"""
192
193    GOA_LEGEND = 4078656646
194    """Grasp of Avarice legend."""
195
196    GOA_MASTER = 3774021532
197    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Enum(enum.Enum):
77class Enum(__enum.Enum):
78    """Builtin Python enum with extra handlings."""
79
80    @property
81    def name(self) -> str:  # type: ignore[override]
82        return self._name_
83
84    @property
85    def value(self) -> typing.Any:  # type: ignore[override]
86        return self._value_
87
88    def __str__(self) -> str:
89        return self._name_
90
91    def __repr__(self) -> str:
92        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
93
94    def __int__(self) -> int:
95        if isinstance(self.value, _ITERABLE):
96            raise TypeError(
97                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
98            )
99        return int(self.value)

Builtin Python enum with extra handlings.

name: str
value: Any
class Factory(aiobungie.interfaces.factory.FactoryInterface):
  61class Factory(interfaces.FactoryInterface):
  62    """The base deserialization factory class for all aiobungie objects.
  63
  64    Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
  65    into a `aiobungie.crates` Python classes.
  66    """
  67
  68    __slots__ = ("_net",)
  69
  70    def __init__(self, net: traits.Netrunner) -> None:
  71        self._net = net
  72
  73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  74        return user.BungieUser(
  75            id=int(data["membershipId"]),
  76            created_at=time.clean_date(data["firstAccess"]),
  77            name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined),
  78            is_deleted=data["isDeleted"],
  79            about=data["about"],
  80            updated_at=time.clean_date(data["lastUpdate"]),
  81            psn_name=data.get("psnDisplayName", None),
  82            stadia_name=data.get("stadiaDisplayName", None),
  83            steam_name=data.get("steamDisplayName", None),
  84            twitch_name=data.get("twitchDisplayName", None),
  85            blizzard_name=data.get("blizzardDisplayName", None),
  86            status=data["statusText"],
  87            locale=data["locale"],
  88            picture=assets.Image(path=str(data["profilePicturePath"])),
  89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  90            unique_name=data.get("uniqueName", None),
  91            theme_id=int(data["profileTheme"]),
  92            show_activity=bool(data["showActivity"]),
  93            theme_name=data["profileThemeName"],
  94            display_title=data["userTitleDisplay"],
  95        )
  96
  97    def deserialize_partial_bungie_user(
  98        self, payload: typedefs.JSONObject
  99    ) -> user.PartialBungieUser:
 100        return user.PartialBungieUser(
 101            net=self._net,
 102            types=[
 103                enums.MembershipType(type_)
 104                for type_ in payload.get("applicableMembershipTypes", [])
 105            ],
 106            name=payload.get("displayName", undefined.Undefined),
 107            id=int(payload["membershipId"]),
 108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 109            is_public=payload["isPublic"],
 110            icon=assets.Image(payload.get("iconPath", "")),
 111            type=enums.MembershipType(payload["membershipType"]),
 112        )
 113
 114    def deserialize_destiny_membership(
 115        self, payload: typedefs.JSONObject
 116    ) -> user.DestinyMembership:
 117        name: undefined.UndefinedOr[str] = undefined.Undefined
 118        if (
 119            raw_name := payload.get("bungieGlobalDisplayName", "")
 120        ) and not typedefs.is_unknown(raw_name):
 121            name = raw_name
 122
 123        return user.DestinyMembership(
 124            net=self._net,
 125            id=int(payload["membershipId"]),
 126            name=name,
 127            code=payload.get("bungieGlobalDisplayNameCode", None),
 128            last_seen_name=payload.get("LastSeenDisplayName")
 129            or payload.get("displayName")
 130            or "",
 131            type=enums.MembershipType(payload["membershipType"]),
 132            is_public=payload["isPublic"],
 133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 134            icon=assets.Image(payload.get("iconPath", "")),
 135            types=[
 136                enums.MembershipType(type_)
 137                for type_ in payload["applicableMembershipTypes"]
 138                if "applicableMembershipTypes" in payload
 139            ],
 140        )
 141
 142    def deserialize_destiny_memberships(
 143        self, data: typedefs.JSONArray
 144    ) -> collections.Sequence[user.DestinyMembership]:
 145        return [self.deserialize_destiny_membership(membership) for membership in data]
 146
 147    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 148
 149        primary_membership_id: typing.Optional[int] = None
 150        if raw_primary_id := data.get("primaryMembershipId"):
 151            primary_membership_id = int(raw_primary_id)
 152
 153        return user.User(
 154            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
 155            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
 156            primary_membership_id=primary_membership_id,
 157        )
 158
 159    def deserialize_searched_user(
 160        self, payload: typedefs.JSONObject
 161    ) -> user.SearchableDestinyUser:
 162        name: undefined.UndefinedOr[str] = undefined.Undefined
 163        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
 164            raw_name
 165        ):
 166            name = raw_name
 167
 168        code: typing.Optional[int] = None
 169        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 170            code = int(raw_code)
 171
 172        bungie_id: typing.Optional[int] = None
 173        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 174            bungie_id = int(raw_bungie_id)
 175
 176        return user.SearchableDestinyUser(
 177            name=name,
 178            code=code,
 179            bungie_id=bungie_id,
 180            memberships=self.deserialize_destiny_memberships(
 181                payload["destinyMemberships"]
 182            ),
 183        )
 184
 185    def deserialize_user_credentials(
 186        self, payload: typedefs.JSONArray
 187    ) -> collections.Sequence[user.UserCredentials]:
 188        return [
 189            user.UserCredentials(
 190                type=enums.CredentialType(int(creds["credentialType"])),
 191                display_name=creds["credentialDisplayName"],
 192                is_public=creds["isPublic"],
 193                self_as_string=creds.get("credentialAsString", undefined.Undefined),
 194            )
 195            for creds in payload
 196        ]
 197
 198    @staticmethod
 199    def set_themese_attrs(
 200        payload: typedefs.JSONArray, /
 201    ) -> typing.Collection[user.UserThemes]:
 202        return [
 203            user.UserThemes(
 204                id=int(entry["userThemeId"]),
 205                name=entry["userThemeName"]
 206                if "userThemeName" in entry
 207                else undefined.Undefined,
 208                description=entry["userThemeDescription"]
 209                if "userThemeDescription" in entry
 210                else undefined.Undefined,
 211            )
 212            for entry in payload
 213        ]
 214
 215    def deserialize_user_themes(
 216        self, payload: typedefs.JSONArray
 217    ) -> collections.Sequence[user.UserThemes]:
 218        return list(self.set_themese_attrs(payload))
 219
 220    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 221
 222        # This is kinda redundant
 223        data = payload
 224
 225        # This is always outside the details.
 226        current_user_map: typing.Optional[
 227            collections.Mapping[str, clans.ClanMember]
 228        ] = None
 229        if raw_current_user_map := payload.get("currentUserMemberMap"):
 230            current_user_map = {
 231                membership_type: self.deserialize_clan_member(membership)
 232                for membership_type, membership in raw_current_user_map.items()
 233            }
 234
 235        try:
 236            data = payload["detail"]
 237        except KeyError:
 238            pass
 239
 240        id = data["groupId"]
 241        name = data["name"]
 242        created_at = data["creationDate"]
 243        member_count = data["memberCount"]
 244        about = data["about"]
 245        motto = data["motto"]
 246        is_public = data["isPublic"]
 247        banner = assets.Image(str(data["bannerPath"]))
 248        avatar = assets.Image(str(data["avatarPath"]))
 249        tags = data["tags"]
 250        type = data["groupType"]
 251
 252        features = data["features"]
 253        features_obj = clans.ClanFeatures(
 254            max_members=features["maximumMembers"],
 255            max_membership_types=features["maximumMembershipsOfGroupType"],
 256            capabilities=features["capabilities"],
 257            membership_types=features["membershipTypes"],
 258            invite_permissions=features["invitePermissionOverride"],
 259            update_banner_permissions=features["updateBannerPermissionOverride"],
 260            update_culture_permissions=features["updateCulturePermissionOverride"],
 261            join_level=features["joinLevel"],
 262        )
 263
 264        information: typedefs.JSONObject = data["clanInfo"]
 265        progression: collections.Mapping[int, progressions.Progression] = {
 266            int(prog_hash): self.deserialize_progressions(prog)
 267            for prog_hash, prog in information["d2ClanProgressions"].items()
 268        }
 269
 270        founder: typedefs.NoneOr[clans.ClanMember] = None
 271        if raw_founder := payload.get("founder"):
 272            founder = self.deserialize_clan_member(raw_founder)
 273
 274        return clans.Clan(
 275            net=self._net,
 276            id=int(id),
 277            name=name,
 278            type=enums.GroupType(type),
 279            created_at=time.clean_date(created_at),
 280            member_count=member_count,
 281            motto=motto,
 282            about=about,
 283            is_public=is_public,
 284            banner=banner,
 285            avatar=avatar,
 286            tags=tags,
 287            features=features_obj,
 288            owner=founder,
 289            progressions=progression,
 290            call_sign=information["clanCallsign"],
 291            banner_data=information["clanBannerData"],
 292            chat_security=data["chatSecurity"],
 293            conversation_id=int(data["conversationId"]),
 294            allow_chat=data["allowChat"],
 295            theme=data["theme"],
 296            current_user_membership=current_user_map,
 297        )
 298
 299    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 300        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 301        return clans.ClanMember(
 302            net=self._net,
 303            last_seen_name=destiny_user.last_seen_name,
 304            id=destiny_user.id,
 305            name=destiny_user.name,
 306            icon=destiny_user.icon,
 307            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 308            group_id=int(data["groupId"]),
 309            joined_at=time.clean_date(data["joinDate"]),
 310            types=destiny_user.types,
 311            is_public=destiny_user.is_public,
 312            type=destiny_user.type,
 313            code=destiny_user.code,
 314            is_online=data["isOnline"],
 315            crossave_override=destiny_user.crossave_override,
 316            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 317            if "bungieNetUserInfo" in data
 318            else None,
 319            member_type=enums.ClanMemberType(int(data["memberType"])),
 320        )
 321
 322    def deserialize_clan_members(
 323        self, data: typedefs.JSONObject, /
 324    ) -> iterators.FlatIterator[clans.ClanMember]:
 325        return iterators.FlatIterator(
 326            [self.deserialize_clan_member(member) for member in data["results"]]
 327        )
 328
 329    def deserialize_group_member(
 330        self, payload: typedefs.JSONObject
 331    ) -> clans.GroupMember:
 332        member = payload["member"]
 333        return clans.GroupMember(
 334            net=self._net,
 335            join_date=time.clean_date(member["joinDate"]),
 336            group_id=int(member["groupId"]),
 337            member_type=enums.ClanMemberType(member["memberType"]),
 338            is_online=member["isOnline"],
 339            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 340            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 341            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 342            group=self.deserialize_clan(payload["group"]),
 343        )
 344
 345    def _deserialize_clan_conversation(
 346        self, payload: typedefs.JSONObject
 347    ) -> clans.ClanConversation:
 348        return clans.ClanConversation(
 349            net=self._net,
 350            id=int(payload["conversationId"]),
 351            group_id=int(payload["groupId"]),
 352            name=(
 353                payload["chatName"]
 354                if not typedefs.is_unknown(payload["chatName"])
 355                else undefined.Undefined
 356            ),
 357            chat_enabled=payload["chatEnabled"],
 358            security=payload["chatSecurity"],
 359        )
 360
 361    def deserialize_clan_conversations(
 362        self, payload: typedefs.JSONArray
 363    ) -> collections.Sequence[clans.ClanConversation]:
 364        return [self._deserialize_clan_conversation(conv) for conv in payload]
 365
 366    def deserialize_app_owner(
 367        self, payload: typedefs.JSONObject
 368    ) -> application.ApplicationOwner:
 369        return application.ApplicationOwner(
 370            net=self._net,
 371            name=payload.get("bungieGlobalDisplayName", undefined.Undefined),
 372            id=int(payload["membershipId"]),
 373            type=enums.MembershipType(payload["membershipType"]),
 374            icon=assets.Image(str(payload["iconPath"])),
 375            is_public=payload["isPublic"],
 376            code=payload.get("bungieGlobalDisplayNameCode", None),
 377        )
 378
 379    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 380        return application.Application(
 381            id=int(payload["applicationId"]),
 382            name=payload["name"],
 383            link=payload["link"],
 384            status=payload["status"],
 385            redirect_url=payload.get("redirectUrl", None),
 386            created_at=time.clean_date(str(payload["creationDate"])),
 387            published_at=time.clean_date(str(payload["firstPublished"])),
 388            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
 389            scope=payload.get("scope", undefined.Undefined),
 390        )
 391
 392    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 393        total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True)
 394        return character.Character(
 395            net=self._net,
 396            id=int(payload["characterId"]),
 397            gender=enums.Gender(payload["genderType"]),
 398            race=enums.Race(payload["raceType"]),
 399            class_type=enums.Class(payload["classType"]),
 400            emblem=assets.Image(str(payload["emblemBackgroundPath"])),
 401            emblem_icon=assets.Image(str(payload["emblemPath"])),
 402            emblem_hash=int(payload["emblemHash"]),
 403            last_played=time.clean_date(payload["dateLastPlayed"]),
 404            total_played_time=total_time,
 405            member_id=int(payload["membershipId"]),
 406            member_type=enums.MembershipType(payload["membershipType"]),
 407            level=payload["baseCharacterLevel"],
 408            title_hash=payload.get("titleRecordHash", None),
 409            light=payload["light"],
 410            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 411        )
 412
 413    def deserialize_profile(
 414        self, payload: typedefs.JSONObject, /
 415    ) -> typing.Optional[profile.Profile]:
 416        if (raw_profile := payload.get("data")) is None:
 417            return None
 418
 419        payload = raw_profile
 420        id = int(payload["userInfo"]["membershipId"])
 421        name = payload["userInfo"]["displayName"]
 422        is_public = payload["userInfo"]["isPublic"]
 423        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 424        last_played = time.clean_date(str(payload["dateLastPlayed"]))
 425        character_ids = [int(cid) for cid in payload["characterIds"]]
 426        power_cap = payload["currentSeasonRewardPowerCap"]
 427
 428        return profile.Profile(
 429            id=int(id),
 430            name=name,
 431            is_public=is_public,
 432            type=type,
 433            last_played=last_played,
 434            character_ids=character_ids,
 435            power_cap=power_cap,
 436            net=self._net,
 437        )
 438
 439    def deserialize_profile_item(
 440        self, payload: typedefs.JSONObject
 441    ) -> profile.ProfileItemImpl:
 442
 443        instance_id: typing.Optional[int] = None
 444        if raw_instance_id := payload.get("itemInstanceId"):
 445            instance_id = int(raw_instance_id)
 446
 447        version_number: typing.Optional[int] = None
 448        if raw_version := payload.get("versionNumber"):
 449            version_number = int(raw_version)
 450
 451        transfer_status = enums.TransferStatus(payload["transferStatus"])
 452
 453        return profile.ProfileItemImpl(
 454            net=self._net,
 455            hash=payload["itemHash"],
 456            quantity=payload["quantity"],
 457            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 458            location=enums.ItemLocation(payload["location"]),
 459            bucket=payload["bucketHash"],
 460            transfer_status=transfer_status,
 461            lockable=payload["lockable"],
 462            state=enums.ItemState(payload["state"]),
 463            dismantel_permissions=payload["dismantlePermission"],
 464            is_wrapper=payload["isWrapper"],
 465            instance_id=instance_id,
 466            version_number=version_number,
 467            ornament_id=payload.get("overrideStyleItemHash"),
 468        )
 469
 470    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 471        return records.Objective(
 472            net=self._net,
 473            hash=payload["objectiveHash"],
 474            visible=payload["visible"],
 475            complete=payload["complete"],
 476            completion_value=payload["completionValue"],
 477            progress=payload.get("progress"),
 478            destination_hash=payload.get("destinationHash"),
 479            activity_hash=payload.get("activityHash"),
 480        )
 481
 482    def deserialize_records(
 483        self,
 484        payload: typedefs.JSONObject,
 485        scores: typing.Optional[records.RecordScores] = None,
 486        **nodes: int,
 487    ) -> records.Record:
 488        objectives: typing.Optional[list[records.Objective]] = None
 489        interval_objectives: typing.Optional[list[records.Objective]] = None
 490        record_state: typedefs.IntAnd[records.RecordState]
 491
 492        record_state = records.RecordState(payload["state"])
 493
 494        if raw_objs := payload.get("objectives"):
 495            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
 496
 497        if raw_interval_objs := payload.get("intervalObjectives"):
 498            interval_objectives = [
 499                self.deserialize_objectives(obj) for obj in raw_interval_objs
 500            ]
 501
 502        return records.Record(
 503            scores=scores,
 504            categories_node_hash=nodes.get("categories_hash", undefined.Undefined),
 505            seals_node_hash=nodes.get("seals_hash", undefined.Undefined),
 506            state=record_state,
 507            objectives=objectives,
 508            interval_objectives=interval_objectives,
 509            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 510            completion_times=payload.get("completedCount", None),
 511            reward_visibility=payload.get("rewardVisibilty", None),
 512        )
 513
 514    def deserialize_character_records(
 515        self,
 516        payload: typedefs.JSONObject,
 517        scores: typing.Optional[records.RecordScores] = None,
 518        record_hashes: typing.Optional[list[int]] = None,
 519    ) -> records.CharacterRecord:
 520
 521        record = self.deserialize_records(payload, scores)
 522        return records.CharacterRecord(
 523            scores=scores,
 524            categories_node_hash=record.categories_node_hash,
 525            seals_node_hash=record.seals_node_hash,
 526            state=record.state,
 527            objectives=record.objectives,
 528            interval_objectives=record.interval_objectives,
 529            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 530            completion_times=payload.get("completedCount"),
 531            reward_visibility=payload.get("rewardVisibilty"),
 532            record_hashes=record_hashes or [],
 533        )
 534
 535    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 536        return character.Dye(
 537            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 538        )
 539
 540    def deserialize_character_customization(
 541        self, payload: typedefs.JSONObject
 542    ) -> character.CustomizationOptions:
 543        return character.CustomizationOptions(
 544            personality=payload["personality"],
 545            face=payload["face"],
 546            skin_color=payload["skinColor"],
 547            lip_color=payload["lipColor"],
 548            eye_color=payload["eyeColor"],
 549            hair_colors=payload.get("hairColors", []),
 550            feature_colors=payload.get("featureColors", []),
 551            decal_color=payload["decalColor"],
 552            wear_helmet=payload["wearHelmet"],
 553            hair_index=payload["hairIndex"],
 554            feature_index=payload["featureIndex"],
 555            decal_index=payload["decalIndex"],
 556        )
 557
 558    def deserialize_character_minimal_equipments(
 559        self, payload: typedefs.JSONObject
 560    ) -> character.MinimalEquipments:
 561        dyes = None
 562        if raw_dyes := payload.get("dyes"):
 563            if raw_dyes:
 564                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
 565        return character.MinimalEquipments(
 566            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 567        )
 568
 569    def deserialize_character_render_data(
 570        self, payload: typedefs.JSONObject, /
 571    ) -> character.RenderedData:
 572        return character.RenderedData(
 573            net=self._net,
 574            customization=self.deserialize_character_customization(
 575                payload["customization"]
 576            ),
 577            custom_dyes=[
 578                self.deserialize_character_dye(dye)
 579                for dye in payload["customDyes"]
 580                if dye
 581            ],
 582            equipment=[
 583                self.deserialize_character_minimal_equipments(equipment)
 584                for equipment in payload["peerView"]["equipment"]
 585            ],
 586        )
 587
 588    def deserialize_available_activity(
 589        self, payload: typedefs.JSONObject
 590    ) -> activity.AvailableActivity:
 591        return activity.AvailableActivity(
 592            hash=payload["activityHash"],
 593            is_new=payload["isNew"],
 594            is_completed=payload["isCompleted"],
 595            is_visible=payload["isVisible"],
 596            display_level=payload.get("displayLevel"),
 597            recommended_light=payload.get("recommendedLight"),
 598            difficulty=activity.Difficulty(payload["difficultyTier"]),
 599            can_join=payload["canJoin"],
 600            can_lead=payload["canLead"],
 601        )
 602
 603    def deserialize_character_activity(
 604        self, payload: typedefs.JSONObject
 605    ) -> activity.CharacterActivity:
 606        current_mode: typing.Optional[enums.GameMode] = None
 607        if raw_current_mode := payload.get("currentActivityModeType"):
 608            current_mode = enums.GameMode(raw_current_mode)
 609
 610        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
 611        if raw_current_modes := payload.get("currentActivityModeTypes"):
 612            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
 613
 614        return activity.CharacterActivity(
 615            date_started=time.clean_date(payload["dateActivityStarted"]),
 616            current_hash=payload["currentActivityHash"],
 617            current_mode_hash=payload["currentActivityModeHash"],
 618            current_mode=current_mode,
 619            current_mode_hashes=payload.get("currentActivityModeHashes"),
 620            current_mode_types=current_mode_types,
 621            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 622            last_story_hash=payload["lastCompletedStoryHash"],
 623            available_activities=[
 624                self.deserialize_available_activity(activity_)
 625                for activity_ in payload["availableActivities"]
 626            ],
 627        )
 628
 629    def deserialize_profile_items(
 630        self, payload: typedefs.JSONObject, /
 631    ) -> list[profile.ProfileItemImpl]:
 632        return [self.deserialize_profile_item(item) for item in payload["items"]]
 633
 634    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 635        return records.Node(
 636            state=int(payload["state"]),
 637            objective=self.deserialize_objectives(payload["objective"])
 638            if "objective" in payload
 639            else None,
 640            progress_value=int(payload["progressValue"]),
 641            completion_value=int(payload["completionValue"]),
 642            record_category_score=int(payload["recordCategoryScore"])
 643            if "recordCategoryScore" in payload
 644            else None,
 645        )
 646
 647    @staticmethod
 648    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 649        recent_collectibles: typing.Optional[collections.Collection[int]] = None
 650        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 651            recent_collectibles = [
 652                int(item_hash) for item_hash in raw_recent_collectibles
 653            ]
 654
 655        collectibles: dict[int, int] = {}
 656        for item_hash, mapping in payload["collectibles"].items():
 657            collectibles[int(item_hash)] = int(mapping["state"])
 658
 659        return items.Collectible(
 660            recent_collectibles=recent_collectibles,
 661            collectibles=collectibles,
 662            collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]),
 663            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 664        )
 665
 666    @staticmethod
 667    def _deserialize_currencies(
 668        payload: typedefs.JSONObject,
 669    ) -> collections.Sequence[items.Currency]:
 670        return [
 671            items.Currency(hash=int(item_hash), amount=int(amount))
 672            for item_hash, amount in payload["itemQuantities"].items()
 673        ]
 674
 675    def deserialize_progressions(
 676        self, payload: typedefs.JSONObject
 677    ) -> progressions.Progression:
 678        return progressions.Progression(
 679            hash=int(payload["progressionHash"]),
 680            level=int(payload["level"]),
 681            cap=int(payload["levelCap"]),
 682            daily_limit=int(payload["dailyLimit"]),
 683            weekly_limit=int(payload["weeklyLimit"]),
 684            current_progress=int(payload["currentProgress"]),
 685            daily_progress=int(payload["dailyProgress"]),
 686            needed=int(payload["progressToNextLevel"]),
 687            next_level=int(payload["nextLevelAt"]),
 688        )
 689
 690    def _deserialize_factions(
 691        self, payload: typedefs.JSONObject
 692    ) -> progressions.Factions:
 693        progs = self.deserialize_progressions(payload)
 694        return progressions.Factions(
 695            hash=progs.hash,
 696            level=progs.level,
 697            cap=progs.cap,
 698            daily_limit=progs.daily_limit,
 699            weekly_limit=progs.weekly_limit,
 700            current_progress=progs.current_progress,
 701            daily_progress=progs.daily_progress,
 702            needed=progs.needed,
 703            next_level=progs.next_level,
 704            faction_hash=payload["factionHash"],
 705            faction_vendor_hash=payload["factionVendorIndex"],
 706        )
 707
 708    def _deserialize_milestone_available_quest(
 709        self, payload: typedefs.JSONObject
 710    ) -> milestones.MilestoneQuest:
 711        return milestones.MilestoneQuest(
 712            item_hash=payload["questItemHash"],
 713            status=self._deserialize_milestone_quest_status(payload["status"]),
 714        )
 715
 716    def _deserialize_milestone_activity(
 717        self, payload: typedefs.JSONObject
 718    ) -> milestones.MilestoneActivity:
 719
 720        phases: typing.Optional[
 721            collections.Sequence[milestones.MilestoneActivityPhase]
 722        ] = None
 723        if raw_phases := payload.get("phases"):
 724            phases = [
 725                milestones.MilestoneActivityPhase(
 726                    is_completed=obj["complete"], hash=obj["phaseHash"]
 727                )
 728                for obj in raw_phases
 729            ]
 730
 731        return milestones.MilestoneActivity(
 732            hash=payload["activityHash"],
 733            challenges=[
 734                self.deserialize_objectives(obj["objective"])
 735                for obj in payload["challenges"]
 736            ],
 737            modifier_hashes=payload.get("modifierHashes"),
 738            boolean_options=payload.get("booleanActivityOptions"),
 739            phases=phases,
 740        )
 741
 742    def _deserialize_milestone_quest_status(
 743        self, payload: typedefs.JSONObject
 744    ) -> milestones.QuestStatus:
 745        return milestones.QuestStatus(
 746            net=self._net,
 747            quest_hash=payload["questHash"],
 748            step_hash=payload["stepHash"],
 749            step_objectives=[
 750                self.deserialize_objectives(objective)
 751                for objective in payload["stepObjectives"]
 752            ],
 753            is_tracked=payload["tracked"],
 754            is_completed=payload["completed"],
 755            started=payload["started"],
 756            item_instance_id=payload["itemInstanceId"],
 757            vendor_hash=payload.get("vendorHash"),
 758            is_redeemed=payload["redeemed"],
 759        )
 760
 761    def _deserialize_milestone_rewards(
 762        self, payload: typedefs.JSONObject
 763    ) -> milestones.MilestoneReward:
 764        return milestones.MilestoneReward(
 765            category_hash=payload["rewardCategoryHash"],
 766            entries=[
 767                milestones.MilestoneRewardEntry(
 768                    entry_hash=entry["rewardEntryHash"],
 769                    is_earned=entry["earned"],
 770                    is_redeemed=entry["redeemed"],
 771                )
 772                for entry in payload["entries"]
 773            ],
 774        )
 775
 776    def deserialize_milestone(
 777        self, payload: typedefs.JSONObject
 778    ) -> milestones.Milestone:
 779        start_date: typing.Optional[datetime.datetime] = None
 780        if raw_start_date := payload.get("startDate"):
 781            start_date = time.clean_date(raw_start_date)
 782
 783        end_date: typing.Optional[datetime.datetime] = None
 784        if raw_end_date := payload.get("endDate"):
 785            end_date = time.clean_date(raw_end_date)
 786
 787        rewards: typing.Optional[
 788            collections.Collection[milestones.MilestoneReward]
 789        ] = None
 790        if raw_rewards := payload.get("rewards"):
 791            rewards = [
 792                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 793            ]
 794
 795        activities: typing.Optional[
 796            collections.Sequence[milestones.MilestoneActivity]
 797        ] = None
 798        if raw_activities := payload.get("activities"):
 799            activities = [
 800                self._deserialize_milestone_activity(active)
 801                for active in raw_activities
 802            ]
 803
 804        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
 805        if raw_quests := payload.get("availableQuests"):
 806            quests = [
 807                self._deserialize_milestone_available_quest(quest)
 808                for quest in raw_quests
 809            ]
 810
 811        vendors: typing.Optional[
 812            collections.Sequence[milestones.MilestoneVendor]
 813        ] = None
 814        if raw_vendors := payload.get("vendors"):
 815            vendors = [
 816                milestones.MilestoneVendor(
 817                    vendor_hash=vendor["vendorHash"],
 818                    preview_itemhash=vendor.get("previewItemHash"),
 819                )
 820                for vendor in raw_vendors
 821            ]
 822
 823        return milestones.Milestone(
 824            hash=payload["milestoneHash"],
 825            start_date=start_date,
 826            end_date=end_date,
 827            order=payload["order"],
 828            rewards=rewards,
 829            available_quests=quests,
 830            activities=activities,
 831            vendors=vendors,
 832        )
 833
 834    def _deserialize_artifact_tiers(
 835        self, payload: typedefs.JSONObject
 836    ) -> season.ArtifactTier:
 837        return season.ArtifactTier(
 838            hash=payload["tierHash"],
 839            is_unlocked=payload["isUnlocked"],
 840            points_to_unlock=payload["pointsToUnlock"],
 841            items=[
 842                season.ArtifactTierItem(
 843                    hash=item["itemHash"], is_active=item["isActive"]
 844                )
 845                for item in payload["items"]
 846            ],
 847        )
 848
 849    def deserialize_characters(
 850        self, payload: typedefs.JSONObject
 851    ) -> collections.Mapping[int, character.Character]:
 852        return {
 853            int(char_id): self._set_character_attrs(char)
 854            for char_id, char in payload["data"].items()
 855        }
 856
 857    def deserialize_character(
 858        self, payload: typedefs.JSONObject
 859    ) -> character.Character:
 860        return self._set_character_attrs(payload)
 861
 862    def deserialize_character_equipments(
 863        self, payload: typedefs.JSONObject
 864    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 865        return {
 866            int(char_id): self.deserialize_profile_items(item)
 867            for char_id, item in payload["data"].items()
 868        }
 869
 870    def deserialize_character_activities(
 871        self, payload: typedefs.JSONObject
 872    ) -> collections.Mapping[int, activity.CharacterActivity]:
 873        return {
 874            int(char_id): self.deserialize_character_activity(data)
 875            for char_id, data in payload["data"].items()
 876        }
 877
 878    def deserialize_characters_render_data(
 879        self, payload: typedefs.JSONObject
 880    ) -> collections.Mapping[int, character.RenderedData]:
 881        return {
 882            int(char_id): self.deserialize_character_render_data(data)
 883            for char_id, data in payload["data"].items()
 884        }
 885
 886    def deserialize_character_progressions(
 887        self, payload: typedefs.JSONObject
 888    ) -> character.CharacterProgression:
 889        progressions_ = {
 890            int(prog_id): self.deserialize_progressions(prog)
 891            for prog_id, prog in payload["progressions"].items()
 892        }
 893
 894        factions = {
 895            int(faction_id): self._deserialize_factions(faction)
 896            for faction_id, faction in payload["factions"].items()
 897        }
 898
 899        milestones_ = {
 900            int(milestone_hash): self.deserialize_milestone(milestone)
 901            for milestone_hash, milestone in payload["milestones"].items()
 902        }
 903
 904        uninstanced_item_objectives = {
 905            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 906            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 907        }
 908
 909        artifact = payload["seasonalArtifact"]
 910        seasonal_artifact = season.CharacterScopedArtifact(
 911            hash=artifact["artifactHash"],
 912            points_used=artifact["pointsUsed"],
 913            reset_count=artifact["resetCount"],
 914            tiers=[
 915                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 916            ],
 917        )
 918        checklists = payload["checklists"]
 919
 920        return character.CharacterProgression(
 921            progressions=progressions_,
 922            factions=factions,
 923            checklists=checklists,
 924            milestones=milestones_,
 925            seasonal_artifact=seasonal_artifact,
 926            uninstanced_item_objectives=uninstanced_item_objectives,
 927        )
 928
 929    def deserialize_character_progressions_mapping(
 930        self, payload: typedefs.JSONObject
 931    ) -> collections.Mapping[int, character.CharacterProgression]:
 932        character_progressions: collections.Mapping[
 933            int, character.CharacterProgression
 934        ] = {}
 935        for char_id, data in payload["data"].items():
 936            # A little hack to stop mypy complaining about Mapping <-> dict
 937            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
 938        return character_progressions
 939
 940    def deserialize_characters_records(
 941        self,
 942        payload: typedefs.JSONObject,
 943    ) -> collections.Mapping[int, records.CharacterRecord]:
 944
 945        return {
 946            int(rec_id): self.deserialize_character_records(
 947                rec, record_hashes=payload.get("featuredRecordHashes")
 948            )
 949            for rec_id, rec in payload["records"].items()
 950        }
 951
 952    def deserialize_profile_records(
 953        self, payload: typedefs.JSONObject
 954    ) -> collections.Mapping[int, records.Record]:
 955        raw_profile_records = payload["data"]
 956        scores = records.RecordScores(
 957            current_score=raw_profile_records["score"],
 958            legacy_score=raw_profile_records["legacyScore"],
 959            lifetime_score=raw_profile_records["lifetimeScore"],
 960        )
 961        return {
 962            int(record_id): self.deserialize_records(
 963                record,
 964                scores,
 965                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 966                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 967            )
 968            for record_id, record in raw_profile_records["records"].items()
 969        }
 970
 971    def _deserialize_craftable_socket_plug(
 972        self, payload: typedefs.JSONObject
 973    ) -> items.CraftableSocketPlug:
 974        return items.CraftableSocketPlug(
 975            item_hash=int(payload["plugItemHash"]),
 976            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 977        )
 978
 979    def _deserialize_craftable_socket(
 980        self, payload: typedefs.JSONObject
 981    ) -> items.CraftableSocket:
 982
 983        plugs: list[items.CraftableSocketPlug] = []
 984        if raw_plug := payload.get("plug"):
 985            plugs.extend(
 986                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 987            )
 988
 989        return items.CraftableSocket(
 990            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 991        )
 992
 993    def _deserialize_craftable_item(
 994        self, payload: typedefs.JSONObject
 995    ) -> items.CraftableItem:
 996
 997        return items.CraftableItem(
 998            is_visible=payload["visible"],
 999            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
1000            sockets=[
1001                self._deserialize_craftable_socket(socket)
1002                for socket in payload["sockets"]
1003            ],
1004        )
1005
1006    def deserialize_craftables_component(
1007        self, payload: typedefs.JSONObject
1008    ) -> components.CraftablesComponent:
1009        return components.CraftablesComponent(
1010            net=self._net,
1011            craftables={
1012                int(item_id): self._deserialize_craftable_item(item)
1013                for item_id, item in payload["craftables"].items()
1014                if item is not None
1015            },
1016            crafting_root_node_hash=payload["craftingRootNodeHash"],
1017        )
1018
1019    def deserialize_components(  # noqa: C901 Too complex.
1020        self, payload: typedefs.JSONObject
1021    ) -> components.Component:
1022
1023        profile_: typing.Optional[profile.Profile] = None
1024        if raw_profile := payload.get("profile"):
1025            profile_ = self.deserialize_profile(raw_profile)
1026
1027        profile_progression: typing.Optional[profile.ProfileProgression] = None
1028        if raw_profile_progression := payload.get("profileProgression"):
1029            profile_progression = self.deserialize_profile_progression(
1030                raw_profile_progression
1031            )
1032
1033        profile_currencies: typing.Optional[
1034            collections.Sequence[profile.ProfileItemImpl]
1035        ] = None
1036        if raw_profile_currencies := payload.get("profileCurrencies"):
1037            if "data" in raw_profile_currencies:
1038                profile_currencies = self.deserialize_profile_items(
1039                    raw_profile_currencies["data"]
1040                )
1041
1042        profile_inventories: typing.Optional[
1043            collections.Sequence[profile.ProfileItemImpl]
1044        ] = None
1045        if raw_profile_inventories := payload.get("profileInventory"):
1046            if "data" in raw_profile_inventories:
1047                profile_inventories = self.deserialize_profile_items(
1048                    raw_profile_inventories["data"]
1049                )
1050
1051        profile_records: typing.Optional[
1052            collections.Mapping[int, records.Record]
1053        ] = None
1054
1055        if raw_profile_records_ := payload.get("profileRecords"):
1056            profile_records = self.deserialize_profile_records(raw_profile_records_)
1057
1058        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1059        if raw_characters := payload.get("characters"):
1060            characters = self.deserialize_characters(raw_characters)
1061
1062        character_records: typing.Optional[
1063            collections.Mapping[int, records.CharacterRecord]
1064        ] = None
1065
1066        if raw_character_records := payload.get("characterRecords"):
1067            # Had to do it in two steps..
1068            to_update: typedefs.JSONObject = {}
1069            for _, data in raw_character_records["data"].items():
1070                for record_id, record in data.items():
1071                    to_update[record_id] = record
1072
1073            character_records = {
1074                int(rec_id): self.deserialize_character_records(
1075                    rec, record_hashes=to_update.get("featuredRecordHashes")
1076                )
1077                for rec_id, rec in to_update["records"].items()
1078            }
1079
1080        character_equipments: typing.Optional[
1081            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1082        ] = None
1083        if raw_character_equips := payload.get("characterEquipment"):
1084            character_equipments = self.deserialize_character_equipments(
1085                raw_character_equips
1086            )
1087
1088        character_inventories: typing.Optional[
1089            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1090        ] = None
1091        if raw_character_inventories := payload.get("characterInventories"):
1092            if "data" in raw_character_inventories:
1093                character_inventories = self.deserialize_character_equipments(
1094                    raw_character_inventories
1095                )
1096
1097        character_activities: typing.Optional[
1098            collections.Mapping[int, activity.CharacterActivity]
1099        ] = None
1100        if raw_char_acts := payload.get("characterActivities"):
1101            character_activities = self.deserialize_character_activities(raw_char_acts)
1102
1103        character_render_data: typing.Optional[
1104            collections.Mapping[int, character.RenderedData]
1105        ] = None
1106        if raw_character_render_data := payload.get("characterRenderData"):
1107            character_render_data = self.deserialize_characters_render_data(
1108                raw_character_render_data
1109            )
1110
1111        character_progressions: typing.Optional[
1112            collections.Mapping[int, character.CharacterProgression]
1113        ] = None
1114
1115        if raw_character_progressions := payload.get("characterProgressions"):
1116            character_progressions = self.deserialize_character_progressions_mapping(
1117                raw_character_progressions
1118            )
1119
1120        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1121        if raw_profile_string_vars := payload.get("profileStringVariables"):
1122            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1123
1124        character_string_vars: typing.Optional[
1125            collections.Mapping[int, collections.Mapping[int, int]]
1126        ] = None
1127        if raw_character_string_vars := payload.get("characterStringVariables"):
1128            character_string_vars = {
1129                int(char_id): data["integerValuesByHash"]
1130                for char_id, data in raw_character_string_vars["data"].items()
1131            }
1132
1133        metrics: typing.Optional[
1134            collections.Sequence[
1135                collections.Mapping[
1136                    int, tuple[bool, typing.Optional[records.Objective]]
1137                ]
1138            ]
1139        ] = None
1140        root_node_hash: typing.Optional[int] = None
1141
1142        if raw_metrics := payload.get("metrics"):
1143            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1144            metrics = [
1145                {
1146                    int(metrics_hash): (
1147                        data["invisible"],
1148                        self.deserialize_objectives(data["objectiveProgress"])
1149                        if "objectiveProgress" in data
1150                        else None,
1151                    )
1152                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1153                }
1154            ]
1155        transitory: typing.Optional[fireteams.FireteamParty] = None
1156        if raw_transitory := payload.get("profileTransitoryData"):
1157            if "data" in raw_transitory:
1158                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1159
1160        item_components: typing.Optional[components.ItemsComponent] = None
1161        if raw_item_components := payload.get("itemComponents"):
1162            item_components = self.deserialize_items_component(raw_item_components)
1163
1164        profile_plugsets: typing.Optional[
1165            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1166        ] = None
1167
1168        if raw_profile_plugs := payload.get("profilePlugSets"):
1169            profile_plugsets = {
1170                int(index): [self.deserialize_plug_item_state(state) for state in data]
1171                for index, data in raw_profile_plugs["data"]["plugs"].items()
1172            }
1173
1174        character_plugsets: typing.Optional[
1175            collections.Mapping[
1176                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1177            ]
1178        ] = None
1179        if raw_char_plugsets := payload.get("characterPlugSets"):
1180            character_plugsets = {
1181                int(char_id): {
1182                    int(index): [
1183                        self.deserialize_plug_item_state(state) for state in data
1184                    ]
1185                    for index, data in inner["plugs"].items()
1186                }
1187                for char_id, inner in raw_char_plugsets["data"].items()
1188            }
1189
1190        character_collectibles: typing.Optional[
1191            collections.Mapping[int, items.Collectible]
1192        ] = None
1193        if raw_character_collectibles := payload.get("characterCollectibles"):
1194            character_collectibles = {
1195                int(char_id): self._deserialize_collectible(data)
1196                for char_id, data in raw_character_collectibles["data"].items()
1197            }
1198
1199        profile_collectibles: typing.Optional[items.Collectible] = None
1200        if raw_profile_collectibles := payload.get("profileCollectibles"):
1201            profile_collectibles = self._deserialize_collectible(
1202                raw_profile_collectibles["data"]
1203            )
1204
1205        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1206        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1207            profile_nodes = {
1208                int(node_hash): self._deserialize_node(node)
1209                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1210            }
1211
1212        character_nodes: typing.Optional[
1213            collections.Mapping[int, collections.Mapping[int, records.Node]]
1214        ] = None
1215        if raw_character_nodes := payload.get("characterPresentationNodes"):
1216            character_nodes = {
1217                int(char_id): {
1218                    int(node_hash): self._deserialize_node(node)
1219                    for node_hash, node in each_character["nodes"].items()
1220                }
1221                for char_id, each_character in raw_character_nodes["data"].items()
1222            }
1223
1224        platform_silver: typing.Optional[
1225            collections.Mapping[str, profile.ProfileItemImpl]
1226        ] = None
1227        if raw_platform_silver := payload.get("platformSilver"):
1228            if "data" in raw_platform_silver:
1229                platform_silver = {
1230                    platform_name: self.deserialize_profile_item(item)
1231                    for platform_name, item in raw_platform_silver["data"][
1232                        "platformSilver"
1233                    ].items()
1234                }
1235
1236        character_currency_lookups: typing.Optional[
1237            collections.Mapping[int, collections.Sequence[items.Currency]]
1238        ] = None
1239        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1240            if "data" in raw_char_lookups:
1241                character_currency_lookups = {
1242                    int(char_id): self._deserialize_currencies(currencie)
1243                    for char_id, currencie in raw_char_lookups["data"].items()
1244                }
1245
1246        character_craftables: typing.Optional[
1247            collections.Mapping[int, components.CraftablesComponent]
1248        ] = None
1249        if raw_character_craftables := payload.get("characterCraftables"):
1250
1251            if "data" in raw_character_craftables:
1252                character_craftables = {
1253                    int(char_id): self.deserialize_craftables_component(craftable)
1254                    for char_id, craftable in raw_character_craftables["data"].items()
1255                }
1256
1257        return components.Component(
1258            profiles=profile_,
1259            profile_progression=profile_progression,
1260            profile_currencies=profile_currencies,
1261            profile_inventories=profile_inventories,
1262            profile_records=profile_records,
1263            characters=characters,
1264            character_records=character_records,
1265            character_equipments=character_equipments,
1266            character_inventories=character_inventories,
1267            character_activities=character_activities,
1268            character_render_data=character_render_data,
1269            character_progressions=character_progressions,
1270            profile_string_variables=profile_string_vars,
1271            character_string_variables=character_string_vars,
1272            metrics=metrics,
1273            root_node_hash=root_node_hash,
1274            transitory=transitory,
1275            item_components=item_components,
1276            profile_plugsets=profile_plugsets,
1277            character_plugsets=character_plugsets,
1278            character_collectibles=character_collectibles,
1279            profile_collectibles=profile_collectibles,
1280            profile_nodes=profile_nodes,
1281            character_nodes=character_nodes,
1282            platform_silver=platform_silver,
1283            character_currency_lookups=character_currency_lookups,
1284            character_craftables=character_craftables,
1285        )
1286
1287    def deserialize_items_component(
1288        self, payload: typedefs.JSONObject
1289    ) -> components.ItemsComponent:
1290        instances: typing.Optional[
1291            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1292        ] = None
1293        if raw_instances := payload.get("instances"):
1294            instances = [
1295                {
1296                    int(ins_id): self.deserialize_instanced_item(item)
1297                    for ins_id, item in raw_instances["data"].items()
1298                }
1299            ]
1300
1301        render_data: typing.Optional[
1302            collections.Mapping[int, tuple[bool, dict[int, int]]]
1303        ] = None
1304        if raw_render_data := payload.get("renderData"):
1305            render_data = {
1306                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1307                for ins_id, data in raw_render_data["data"].items()
1308            }
1309
1310        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1311        if raw_stats := payload.get("stats"):
1312            builder: collections.Mapping[int, items.ItemStatsView] = {}
1313            for ins_id, stat in raw_stats["data"].items():
1314                for _, items_ in stat.items():
1315                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1316            stats = builder
1317
1318        sockets: typing.Optional[
1319            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1320        ] = None
1321        if raw_sockets := payload.get("sockets"):
1322            sockets = {
1323                int(ins_id): [
1324                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1325                ]
1326                for ins_id, item in raw_sockets["data"].items()
1327            }
1328
1329        objeectives: typing.Optional[
1330            collections.Mapping[int, collections.Sequence[records.Objective]]
1331        ] = None
1332        if raw_objectives := payload.get("objectives"):
1333            objeectives = {
1334                int(ins_id): [self.deserialize_objectives(objective)]
1335                for ins_id, data in raw_objectives["data"].items()
1336                for objective in data["objectives"]
1337            }
1338
1339        perks: typing.Optional[
1340            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1341        ] = None
1342        if raw_perks := payload.get("perks"):
1343            perks = {
1344                int(ins_id): [
1345                    self.deserialize_item_perk(perk) for perk in item["perks"]
1346                ]
1347                for ins_id, item in raw_perks["data"].items()
1348            }
1349
1350        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1351        if raw_plug_states := payload.get("plugStates"):
1352            pending_states: list[items.PlugItemState] = []
1353            for _, plug in raw_plug_states["data"].items():
1354                pending_states.append(self.deserialize_plug_item_state(plug))
1355            plug_states = pending_states
1356
1357        reusable_plugs: typing.Optional[
1358            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1359        ] = None
1360        if raw_re_plugs := payload.get("reusablePlugs"):
1361            reusable_plugs = {
1362                int(ins_id): [
1363                    self.deserialize_plug_item_state(state) for state in inner
1364                ]
1365                for ins_id, plug in raw_re_plugs["data"].items()
1366                for inner in list(plug["plugs"].values())
1367            }
1368
1369        plug_objectives: typing.Optional[
1370            collections.Mapping[
1371                int, collections.Mapping[int, collections.Collection[records.Objective]]
1372            ]
1373        ] = None
1374        if raw_plug_objectives := payload.get("plugObjectives"):
1375            plug_objectives = {
1376                int(ins_id): {
1377                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1378                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1379                }
1380                for ins_id, inner in raw_plug_objectives["data"].items()
1381            }
1382
1383        return components.ItemsComponent(
1384            sockets=sockets,
1385            stats=stats,
1386            render_data=render_data,
1387            instances=instances,
1388            objectives=objeectives,
1389            perks=perks,
1390            plug_states=plug_states,
1391            reusable_plugs=reusable_plugs,
1392            plug_objectives=plug_objectives,
1393        )
1394
1395    def deserialize_character_component(  # type: ignore[call-arg]
1396        self, payload: typedefs.JSONObject
1397    ) -> components.CharacterComponent:
1398
1399        character_: typing.Optional[character.Character] = None
1400        if raw_singuler_character := payload.get("character"):
1401            character_ = self.deserialize_character(raw_singuler_character["data"])
1402
1403        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1404        if raw_inventory := payload.get("inventory"):
1405            if "data" in raw_inventory:
1406                inventory = self.deserialize_profile_items(raw_inventory["data"])
1407
1408        activities: typing.Optional[activity.CharacterActivity] = None
1409        if raw_activities := payload.get("activities"):
1410            activities = self.deserialize_character_activity(raw_activities["data"])
1411
1412        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1413        if raw_equipments := payload.get("equipment"):
1414            equipment = self.deserialize_profile_items(raw_equipments["data"])
1415
1416        progressions_: typing.Optional[character.CharacterProgression] = None
1417        if raw_progressions := payload.get("progressions"):
1418            progressions_ = self.deserialize_character_progressions(
1419                raw_progressions["data"]
1420            )
1421
1422        render_data: typing.Optional[character.RenderedData] = None
1423        if raw_render_data := payload.get("renderData"):
1424            render_data = self.deserialize_character_render_data(
1425                raw_render_data["data"]
1426            )
1427
1428        character_records: typing.Optional[
1429            collections.Mapping[int, records.CharacterRecord]
1430        ] = None
1431        if raw_char_records := payload.get("records"):
1432            character_records = self.deserialize_characters_records(
1433                raw_char_records["data"]
1434            )
1435
1436        item_components: typing.Optional[components.ItemsComponent] = None
1437        if raw_item_components := payload.get("itemComponents"):
1438            item_components = self.deserialize_items_component(raw_item_components)
1439
1440        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1441        if raw_nodes := payload.get("presentationNodes"):
1442            nodes = {
1443                int(node_hash): self._deserialize_node(node)
1444                for node_hash, node in raw_nodes["data"]["nodes"].items()
1445            }
1446
1447        collectibles: typing.Optional[items.Collectible] = None
1448        if raw_collectibles := payload.get("collectibles"):
1449            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1450
1451        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1452        if raw_currencies := payload.get("currencyLookups"):
1453            if "data" in raw_currencies:
1454                currency_lookups = self._deserialize_currencies(raw_currencies)
1455
1456        return components.CharacterComponent(
1457            activities=activities,
1458            equipment=equipment,
1459            inventory=inventory,
1460            progressions=progressions_,
1461            render_data=render_data,
1462            character=character_,
1463            character_records=character_records,
1464            profile_records=None,
1465            item_components=item_components,
1466            currency_lookups=currency_lookups,
1467            collectibles=collectibles,
1468            nodes=nodes,
1469        )
1470
1471    def _set_entity_attrs(
1472        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1473    ) -> entity.Entity:
1474
1475        name: undefined.UndefinedOr[str] = undefined.Undefined
1476        description: undefined.UndefinedOr[str] = undefined.Undefined
1477
1478        if properties := payload[key]:
1479            if (raw_name := properties["name"]) is not typedefs.Unknown:
1480                name = raw_name
1481
1482            if (
1483                raw_description := properties["description"]
1484            ) and not typedefs.is_unknown(raw_description):
1485                description = raw_description
1486
1487        return entity.Entity(
1488            net=self._net,
1489            hash=payload["hash"],
1490            index=payload["index"],
1491            name=name,
1492            description=description,
1493            has_icon=properties["hasIcon"],
1494            icon=assets.Image(properties["icon"] if "icon" in properties else None),
1495        )
1496
1497    def deserialize_inventory_results(
1498        self, payload: typedefs.JSONObject
1499    ) -> iterators.FlatIterator[entity.SearchableEntity]:
1500        suggested_words: list[str] = payload["suggestedWords"]
1501
1502        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1503            return s if not typedefs.is_unknown(s) else undefined.Undefined
1504
1505        return iterators.FlatIterator(
1506            [
1507                entity.SearchableEntity(
1508                    net=self._net,
1509                    hash=data["hash"],
1510                    entity_type=data["entityType"],
1511                    weight=data["weight"],
1512                    suggested_words=suggested_words,
1513                    name=data["displayProperties"]["name"],
1514                    has_icon=data["displayProperties"]["hasIcon"],
1515                    description=_check_unknown(
1516                        data["displayProperties"]["description"]
1517                    ),
1518                    icon=assets.Image(data["displayProperties"]["icon"]),
1519                )
1520                for data in payload["results"]["results"]
1521            ]
1522        )
1523
1524    def _deserialize_inventory_item_objects(
1525        self, payload: typedefs.JSONObject
1526    ) -> entity.InventoryEntityObjects:
1527        return entity.InventoryEntityObjects(
1528            action=payload.get("action"),
1529            set_data=payload.get("setData"),
1530            stats=payload.get("stats"),
1531            equipping_block=payload.get("equippingBlock"),
1532            translation_block=payload.get("translationBlock"),
1533            preview=payload.get("preview"),
1534            quality=payload.get("quality"),
1535            value=payload.get("value"),
1536            source_data=payload.get("sourceData"),
1537            objectives=payload.get("objectives"),
1538            plug=payload.get("plug"),
1539            metrics=payload.get("metrics"),
1540            gearset=payload.get("gearset"),
1541            sack=payload.get("sack"),
1542            sockets=payload.get("sockets"),
1543            summary=payload.get("summary"),
1544            talent_gird=payload.get("talentGrid"),
1545            investments_stats=payload.get("investmentStats"),
1546            perks=payload.get("perks"),
1547            animations=payload.get("animations", []),
1548            links=payload.get("links", []),
1549        )
1550
1551    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1552        self, payload: typedefs.JSONObject, /
1553    ) -> entity.InventoryEntity:
1554
1555        props = self._set_entity_attrs(payload)
1556        objects = self._deserialize_inventory_item_objects(payload)
1557
1558        collectible_hash: typing.Optional[int] = None
1559        if raw_collectible_hash := payload.get("collectibleHash"):
1560            collectible_hash = int(raw_collectible_hash)
1561
1562        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1563        if raw_second_icon := payload.get("secondaryIcon"):
1564            secondary_icon = assets.Image(raw_second_icon)
1565
1566        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1567        if raw_second_overlay := payload.get("secondaryOverlay"):
1568            secondary_overlay = assets.Image(raw_second_overlay)
1569
1570        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1571        if raw_second_special := payload.get("secondarySpecial"):
1572            secondary_special = assets.Image(raw_second_special)
1573
1574        screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1575        if raw_screenshot := payload.get("screenshot"):
1576            screenshot = assets.Image(raw_screenshot)
1577
1578        watermark_icon: typing.Optional[assets.Image] = None
1579        if raw_watermark_icon := payload.get("iconWatermark"):
1580            watermark_icon = assets.Image(raw_watermark_icon)
1581
1582        watermark_shelved: typing.Optional[assets.Image] = None
1583        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1584            watermark_shelved = assets.Image(raw_watermark_shelved)
1585
1586        about: undefined.UndefinedOr[str] = undefined.Undefined
1587        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1588            raw_about
1589        ):
1590            about = raw_about
1591
1592        ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined
1593        if (
1594            raw_ui_style := payload.get("uiItemDisplayStyle")
1595        ) and not typedefs.is_unknown(raw_ui_style):
1596            ui_item_style = raw_ui_style
1597
1598        tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined
1599        if (
1600            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1601        ) and not typedefs.is_unknown(raw_tier_and_name):
1602            tier_and_name = raw_tier_and_name
1603
1604        type_name: undefined.UndefinedOr[str] = undefined.Undefined
1605        if (
1606            raw_type_name := payload.get("itemTypeDisplayName")
1607        ) and not typedefs.is_unknown(raw_type_name):
1608            type_name = raw_type_name
1609
1610        display_source: undefined.UndefinedOr[str] = undefined.Undefined
1611        if (
1612            raw_display_source := payload.get("displaySource")
1613        ) and not typedefs.is_unknown(raw_display_source):
1614            display_source = raw_display_source
1615
1616        lorehash: typing.Optional[int] = None
1617        if raw_lore_hash := payload.get("loreHash"):
1618            lorehash = int(raw_lore_hash)
1619
1620        summary_hash: typing.Optional[int] = None
1621        if raw_summary_hash := payload.get("summaryItemHash"):
1622            summary_hash = raw_summary_hash
1623
1624        breaker_type_hash: typing.Optional[int] = None
1625        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1626            breaker_type_hash = int(raw_breaker_type_hash)
1627
1628        damage_types: typing.Optional[collections.Sequence[int]] = None
1629        if raw_damage_types := payload.get("damageTypes"):
1630            damage_types = [int(type_) for type_ in raw_damage_types]
1631
1632        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1633        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1634            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1635
1636        default_damagetype_hash: typing.Optional[int] = None
1637        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1638            default_damagetype_hash = int(raw_defaultdmg_hash)
1639
1640        emblem_objective_hash: typing.Optional[int] = None
1641        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1642            emblem_objective_hash = int(raw_emblem_obj_hash)
1643
1644        tier_type: typing.Optional[enums.TierType] = None
1645        tier: typing.Optional[enums.ItemTier] = None
1646        bucket_hash: typing.Optional[int] = None
1647        recovery_hash: typing.Optional[int] = None
1648        tier_name: undefined.UndefinedOr[str] = undefined.Undefined
1649        isinstance_item: bool = False
1650        expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined
1651        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined
1652        suppress_expiration: bool = False
1653        max_stack_size: typing.Optional[int] = None
1654        stack_label: undefined.UndefinedOr[str] = undefined.Undefined
1655
1656        if inventory := payload.get("inventory"):
1657            tier_type = enums.TierType(int(inventory["tierType"]))
1658            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1659            bucket_hash = int(inventory["bucketTypeHash"])
1660            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1661            tier_name = inventory["tierTypeName"]
1662            isinstance_item = inventory["isInstanceItem"]
1663            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1664            max_stack_size = int(inventory["maxStackSize"])
1665
1666            try:
1667                stack_label = inventory["stackUniqueLabel"]
1668            except KeyError:
1669                pass
1670
1671        return entity.InventoryEntity(
1672            net=self._net,
1673            collectible_hash=collectible_hash,
1674            name=props.name,
1675            about=about,
1676            emblem_objective_hash=emblem_objective_hash,
1677            suppress_expiration=suppress_expiration,
1678            max_stack_size=max_stack_size,
1679            stack_label=stack_label,
1680            tier=tier,
1681            tier_type=tier_type,
1682            tier_name=tier_name,
1683            bucket_hash=bucket_hash,
1684            recovery_bucket_hash=recovery_hash,
1685            isinstance_item=isinstance_item,
1686            expire_in_orbit_message=expire_in_orbit_message,
1687            expiration_tooltip=expire_tool_tip,
1688            lore_hash=lorehash,
1689            type_and_tier_name=tier_and_name,
1690            summary_hash=summary_hash,
1691            ui_display_style=ui_item_style,
1692            type_name=type_name,
1693            breaker_type_hash=breaker_type_hash,
1694            description=props.description,
1695            display_source=display_source,
1696            hash=props.hash,
1697            damage_types=damage_types,
1698            index=props.index,
1699            icon=props.icon,
1700            has_icon=props.has_icon,
1701            screenshot=screenshot,
1702            watermark_icon=watermark_icon,
1703            watermark_shelved=watermark_shelved,
1704            secondary_icon=secondary_icon,
1705            secondary_overlay=secondary_overlay,
1706            secondary_special=secondary_special,
1707            type=enums.ItemType(int(payload["itemType"])),
1708            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1709            trait_ids=[trait for trait in payload.get("traitIds", [])],
1710            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1711            item_class=enums.Class(int(payload["classType"])),
1712            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1713            breaker_type=int(payload["breakerType"]),
1714            default_damagetype=int(payload["defaultDamageType"]),
1715            default_damagetype_hash=default_damagetype_hash,
1716            damagetype_hashes=damagetype_hashes,
1717            tooltip_notifications=payload["tooltipNotifications"],
1718            not_transferable=payload["nonTransferrable"],
1719            allow_actions=payload["allowActions"],
1720            is_equippable=payload["equippable"],
1721            objects=objects,
1722            background_colors=payload.get("backgroundColor", {}),
1723            season_hash=payload.get("seasonHash"),
1724            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1725        )
1726
1727    def deserialize_objective_entity(
1728        self, payload: typedefs.JSONObject, /
1729    ) -> entity.ObjectiveEntity:
1730        props = self._set_entity_attrs(payload)
1731        return entity.ObjectiveEntity(
1732            net=self._net,
1733            hash=props.hash,
1734            index=props.index,
1735            description=props.description,
1736            name=props.name,
1737            has_icon=props.has_icon,
1738            icon=props.icon,
1739            unlock_value_hash=payload["unlockValueHash"],
1740            completion_value=payload["completionValue"],
1741            scope=entity.GatingScope(int(payload["scope"])),
1742            location_hash=payload["locationHash"],
1743            allowed_negative_value=payload["allowNegativeValue"],
1744            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1745            counting_downward=payload["isCountingDownward"],
1746            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1747            progress_description=payload["progressDescription"],
1748            perks=payload["perks"],
1749            stats=payload["stats"],
1750            minimum_visibility=payload["minimumVisibilityThreshold"],
1751            allow_over_completion=payload["allowOvercompletion"],
1752            show_value_style=payload["showValueOnComplete"],
1753            display_only_objective=payload["isDisplayOnlyObjective"],
1754            complete_value_style=entity.ValueUIStyle(
1755                int(payload["completedValueStyle"])
1756            ),
1757            progress_value_style=entity.ValueUIStyle(
1758                int(payload["inProgressValueStyle"])
1759            ),
1760            ui_label=payload["uiLabel"],
1761            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1762        )
1763
1764    def _deserialize_activity_values(
1765        self, payload: typedefs.JSONObject, /
1766    ) -> activity.ActivityValues:
1767        team: typing.Optional[int] = None
1768        if raw_team := payload.get("team"):
1769            team = raw_team["basic"]["value"]
1770        return activity.ActivityValues(
1771            assists=payload["assists"]["basic"]["value"],
1772            deaths=payload["deaths"]["basic"]["value"],
1773            kills=payload["kills"]["basic"]["value"],
1774            is_completed=bool(payload["completed"]["basic"]["value"]),
1775            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1776            efficiency=payload["efficiency"]["basic"]["value"],
1777            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1778            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1779            score=payload["score"]["basic"]["value"],
1780            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1781            team=team,
1782            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1783            fireteam_id=payload["fireteamId"]["basic"]["value"],
1784            start_seconds=payload["startSeconds"]["basic"]["value"],
1785            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1786            player_count=payload["playerCount"]["basic"]["value"],
1787            team_score=payload["teamScore"]["basic"]["value"],
1788        )
1789
1790    def deserialize_activity(
1791        self,
1792        payload: typedefs.JSONObject,
1793        /,
1794    ) -> activity.Activity:
1795        period = time.clean_date(payload["period"])
1796        details = payload["activityDetails"]
1797        ref_id = int(details["referenceId"])
1798        instance_id = int(details["instanceId"])
1799        mode = enums.GameMode(details["mode"])
1800        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1801        is_private = details["isPrivate"]
1802        membership_type = enums.MembershipType(int(details["membershipType"]))
1803
1804        # Since we're using the same fields for post activity method
1805        # this check is required since post activity doesn't values values
1806        values = self._deserialize_activity_values(payload["values"])
1807
1808        return activity.Activity(
1809            net=self._net,
1810            hash=ref_id,
1811            instance_id=instance_id,
1812            mode=mode,
1813            modes=modes,
1814            is_private=is_private,
1815            membership_type=membership_type,
1816            occurred_at=period,
1817            values=values,
1818        )
1819
1820    def deserialize_activities(
1821        self, payload: typedefs.JSONObject
1822    ) -> iterators.FlatIterator[activity.Activity]:
1823        return iterators.FlatIterator(
1824            [
1825                self.deserialize_activity(activity_)
1826                for activity_ in payload["activities"]
1827            ]
1828        )
1829
1830    def deserialize_extended_weapon_values(
1831        self, payload: typedefs.JSONObject
1832    ) -> activity.ExtendedWeaponValues:
1833
1834        assists: typing.Optional[int] = None
1835        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1836            assists = raw_assists["basic"]["value"]
1837        assists_damage: typing.Optional[int] = None
1838
1839        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1840            assists_damage = raw_assists_damage["basic"]["value"]
1841
1842        return activity.ExtendedWeaponValues(
1843            reference_id=int(payload["referenceId"]),
1844            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1845            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1846                "value"
1847            ],
1848            assists=assists,
1849            assists_damage=assists_damage,
1850            precision_kills_percentage=(
1851                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1852                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1853                    "displayValue"
1854                ],
1855            ),
1856        )
1857
1858    def _deserialize_extended_values(
1859        self, payload: typedefs.JSONObject
1860    ) -> activity.ExtendedValues:
1861        weapons: typing.Optional[
1862            collections.Collection[activity.ExtendedWeaponValues]
1863        ] = None
1864
1865        if raw_weapons := payload.get("weapons"):
1866            weapons = [
1867                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1868            ]
1869
1870        return activity.ExtendedValues(
1871            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1872            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1873            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1874            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1875            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1876            weapons=weapons,
1877        )
1878
1879    def deserialize_post_activity_player(
1880        self, payload: typedefs.JSONObject, /
1881    ) -> activity.PostActivityPlayer:
1882        player = payload["player"]
1883
1884        class_hash: typedefs.NoneOr[int] = None
1885        if (class_hash := player.get("classHash")) is not None:
1886            class_hash = class_hash
1887
1888        race_hash: typedefs.NoneOr[int] = None
1889        if (race_hash := player.get("raceHash")) is not None:
1890            race_hash = race_hash
1891
1892        gender_hash: typedefs.NoneOr[int] = None
1893        if (gender_hash := player.get("genderHash")) is not None:
1894            gender_hash = gender_hash
1895
1896        character_class: undefined.UndefinedOr[str] = undefined.Undefined
1897        if (
1898            character_class := player.get("characterClass")
1899        ) and not typedefs.is_unknown(character_class):
1900            character_class = character_class
1901
1902        character_level: typedefs.NoneOr[int] = None
1903        if (character_level := player.get("characterLevel")) is not None:
1904            character_level = character_level
1905
1906        return activity.PostActivityPlayer(
1907            standing=int(payload["standing"]),
1908            score=int(payload["score"]["basic"]["value"]),
1909            character_id=payload["characterId"],
1910            destiny_user=self.deserialize_destiny_membership(
1911                payload["player"]["destinyUserInfo"]
1912            ),
1913            character_class=character_class,
1914            character_level=character_level,
1915            race_hash=race_hash,
1916            gender_hash=gender_hash,
1917            class_hash=class_hash,
1918            light_level=int(payload["player"]["lightLevel"]),
1919            emblem_hash=int(payload["player"]["emblemHash"]),
1920            values=self._deserialize_activity_values(payload["values"]),
1921            extended_values=self._deserialize_extended_values(payload["extended"]),
1922        )
1923
1924    def _deserialize_post_activity_team(
1925        self, payload: typedefs.JSONObject
1926    ) -> activity.PostActivityTeam:
1927        return activity.PostActivityTeam(
1928            id=payload["teamId"],
1929            is_defeated=bool(payload["standing"]["basic"]["value"]),
1930            score=int(payload["score"]["basic"]["value"]),
1931            name=payload["teamName"],
1932        )
1933
1934    def deserialize_post_activity(
1935        self, payload: typedefs.JSONObject
1936    ) -> activity.PostActivity:
1937        period = time.clean_date(payload["period"])
1938        details = payload["activityDetails"]
1939        ref_id = int(details["referenceId"])
1940        instance_id = int(details["instanceId"])
1941        mode = enums.GameMode(details["mode"])
1942        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1943        is_private = details["isPrivate"]
1944        membership_type = enums.MembershipType(int(details["membershipType"]))
1945        return activity.PostActivity(
1946            net=self._net,
1947            hash=ref_id,
1948            membership_type=membership_type,
1949            instance_id=instance_id,
1950            mode=mode,
1951            modes=modes,
1952            is_private=is_private,
1953            occurred_at=period,
1954            starting_phase=int(payload["startingPhaseIndex"]),
1955            players=[
1956                self.deserialize_post_activity_player(player)
1957                for player in payload["entries"]
1958            ],
1959            teams=[
1960                self._deserialize_post_activity_team(team) for team in payload["teams"]
1961            ],
1962        )
1963
1964    def _deserialize_aggregated_activity_values(
1965        self, payload: typedefs.JSONObject
1966    ) -> activity.AggregatedActivityValues:
1967        # This ID is always the same for all aggregated values.
1968        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1969
1970        return activity.AggregatedActivityValues(
1971            id=activity_id,
1972            fastest_completion_time=(
1973                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1974                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1975            ),
1976            completions=int(payload["activityCompletions"]["basic"]["value"]),
1977            kills=int(payload["activityKills"]["basic"]["value"]),
1978            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1979            assists=int(payload["activityAssists"]["basic"]["value"]),
1980            seconds_played=(
1981                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1982                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1983            ),
1984            wins=int(payload["activityWins"]["basic"]["value"]),
1985            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1986            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1987            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1988            best_single_score=int(
1989                payload["activityBestSingleGameScore"]["basic"]["value"]
1990            ),
1991            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1992            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1993            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1994            kd_ratio=float(
1995                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1996            ),
1997            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1998        )
1999
2000    def deserialize_aggregated_activity(
2001        self, payload: typedefs.JSONObject
2002    ) -> activity.AggregatedActivity:
2003        return activity.AggregatedActivity(
2004            hash=int(payload["activityHash"]),
2005            values=self._deserialize_aggregated_activity_values(payload["values"]),
2006        )
2007
2008    def deserialize_aggregated_activities(
2009        self, payload: typedefs.JSONObject
2010    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
2011        return iterators.FlatIterator(
2012            [
2013                self.deserialize_aggregated_activity(activity)
2014                for activity in payload["activities"]
2015            ]
2016        )
2017
2018    def deserialize_linked_profiles(
2019        self, payload: typedefs.JSONObject
2020    ) -> profile.LinkedProfile:
2021        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2022        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2023        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2024
2025        if raw_profile := payload.get("profiles"):
2026            for pfile in raw_profile:
2027                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2028
2029        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2030            for raw_error_pfile in raw_profiles_with_errors:
2031                if error_pfile := raw_error_pfile.get("infoCard"):
2032                    error_profiles_vec.append(
2033                        self.deserialize_destiny_membership(error_pfile)
2034                    )
2035
2036        return profile.LinkedProfile(
2037            net=self._net,
2038            bungie=bungie_user,
2039            profiles=profiles_vec,
2040            profiles_with_errors=error_profiles_vec,
2041        )
2042
2043    def deserialize_clan_banners(
2044        self, payload: typedefs.JSONObject
2045    ) -> collections.Sequence[clans.ClanBanner]:
2046        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2047        if banners := payload.get("clanBannerDecals"):
2048            for k, v in banners.items():
2049                banner_obj = clans.ClanBanner(
2050                    id=int(k),
2051                    foreground=assets.Image(v["foregroundPath"]),
2052                    background=assets.Image(v["backgroundPath"]),
2053                )
2054                banners_seq.append(banner_obj)
2055        return banners_seq
2056
2057    def deserialize_public_milestone_content(
2058        self, payload: typedefs.JSONObject
2059    ) -> milestones.MilestoneContent:
2060        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2061        if raw_categories := payload.get("itemCategories"):
2062            for item in raw_categories:
2063                title = undefined.Undefined
2064                if raw_title := item.get("title"):
2065                    if raw_title != typedefs.Unknown:
2066                        title = raw_title
2067                if raw_hashes := item.get("itemHashes"):
2068                    hashes: collections.Sequence[int] = raw_hashes
2069
2070                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2071
2072        about = undefined.Undefined
2073        if (raw_about := payload["about"]) != typedefs.Unknown:
2074            about = raw_about
2075
2076        status = undefined.Undefined
2077        if (raw_status := payload["status"]) != typedefs.Unknown:
2078            status = raw_status
2079
2080        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2081        if raw_tips := payload.get("tips"):
2082            for raw_tip in raw_tips:
2083                if raw_tip == typedefs.Unknown:
2084                    raw_tip = undefined.Undefined
2085                tips.append(raw_tip)
2086
2087        return milestones.MilestoneContent(
2088            about=about, status=status, tips=tips, items=items_categoris
2089        )
2090
2091    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2092        name = undefined.Undefined
2093        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2094            name = raw_name
2095
2096        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2097
2098        if raw_bungie_user := payload.get("bungieNetUser"):
2099            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2100
2101        return friends.Friend(
2102            net=self._net,
2103            id=int(payload["lastSeenAsMembershipId"]),
2104            name=name,
2105            code=payload.get("bungieGlobalDisplayNameCode"),
2106            relationship=enums.Relationship(payload["relationship"]),
2107            user=bungie_user,
2108            online_status=enums.Presence(payload["onlineStatus"]),
2109            online_title=payload["onlineTitle"],
2110            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2111        )
2112
2113    def deserialize_friends(
2114        self, payload: typedefs.JSONObject
2115    ) -> collections.Sequence[friends.Friend]:
2116        mut_seq: typing.MutableSequence[friends.Friend] = []
2117        if raw_friends := payload.get("friends"):
2118            for friend in raw_friends:
2119                mut_seq.append(self.deserialize_friend(friend))
2120        return mut_seq
2121
2122    def deserialize_friend_requests(
2123        self, payload: typedefs.JSONObject
2124    ) -> friends.FriendRequestView:
2125        incoming: typing.MutableSequence[friends.Friend] = []
2126        outgoing: typing.MutableSequence[friends.Friend] = []
2127
2128        if raw_incoming_requests := payload.get("incomingRequests"):
2129            for incoming_request in raw_incoming_requests:
2130                incoming.append(self.deserialize_friend(incoming_request))
2131
2132        if raw_outgoing_requests := payload.get("outgoingRequests"):
2133            for outgoing_request in raw_outgoing_requests:
2134                outgoing.append(self.deserialize_friend(outgoing_request))
2135
2136        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2137
2138    def _set_fireteam_fields(
2139        self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None
2140    ) -> fireteams.Fireteam:
2141        activity_type = fireteams.FireteamActivity(payload["activityType"])
2142        return fireteams.Fireteam(
2143            id=int(payload["fireteamId"]),
2144            group_id=int(payload["groupId"]),
2145            platform=fireteams.FireteamPlatform(payload["platform"]),
2146            is_immediate=payload["isImmediate"],
2147            activity_type=activity_type,
2148            owner_id=int(payload["ownerMembershipId"]),
2149            player_slot_count=payload["playerSlotCount"],
2150            available_player_slots=payload["availablePlayerSlotCount"],
2151            available_alternate_slots=payload["availableAlternateSlotCount"],
2152            title=payload["title"],
2153            date_created=time.clean_date(payload["dateCreated"]),
2154            is_public=payload["isPublic"],
2155            locale=fireteams.FireteamLanguage(payload["locale"]),
2156            is_valid=payload["isValid"],
2157            last_modified=time.clean_date(payload["datePlayerModified"]),
2158            total_results=total_results or 0,
2159        )
2160
2161    def deserialize_fireteams(
2162        self, payload: typedefs.JSONObject
2163    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2164        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2165
2166        result: list[typedefs.JSONObject]
2167        if not (result := payload["results"]):
2168            return None
2169        for elem in result:
2170            fireteams_.append(
2171                self._set_fireteam_fields(
2172                    elem, total_results=int(payload["totalResults"])
2173                )
2174            )
2175        return fireteams_
2176
2177    def deserialize_fireteam_destiny_users(
2178        self, payload: typedefs.JSONObject
2179    ) -> fireteams.FireteamUser:
2180        destiny_obj = self.deserialize_destiny_membership(payload)
2181        # We could helpers.just return a DestinyMembership object but this is
2182        # missing the fireteam display name and id fields.
2183        return fireteams.FireteamUser(
2184            net=self._net,
2185            id=destiny_obj.id,
2186            code=destiny_obj.code,
2187            icon=destiny_obj.icon,
2188            types=destiny_obj.types,
2189            type=destiny_obj.type,
2190            is_public=destiny_obj.is_public,
2191            crossave_override=destiny_obj.crossave_override,
2192            name=destiny_obj.name,
2193            last_seen_name=destiny_obj.last_seen_name,
2194            fireteam_display_name=payload["FireteamDisplayName"],
2195            fireteam_membership_id=enums.MembershipType(
2196                payload["FireteamMembershipType"]
2197            ),
2198        )
2199
2200    def deserialize_fireteam_members(
2201        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2202    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2203        members_: list[fireteams.FireteamMember] = []
2204        if members := payload.get("Members" if not alternatives else "Alternates"):
2205            for member in members:
2206                bungie_fields = self.deserialize_partial_bungie_user(member)
2207                members_fields = fireteams.FireteamMember(
2208                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2209                    has_microphone=member["hasMicrophone"],
2210                    character_id=int(member["characterId"]),
2211                    date_joined=time.clean_date(member["dateJoined"]),
2212                    last_platform_invite_date=time.clean_date(
2213                        member["lastPlatformInviteAttemptDate"]
2214                    ),
2215                    last_platform_invite_result=int(
2216                        member["lastPlatformInviteAttemptResult"]
2217                    ),
2218                    net=self._net,
2219                    name=bungie_fields.name,
2220                    id=bungie_fields.id,
2221                    icon=bungie_fields.icon,
2222                    is_public=bungie_fields.is_public,
2223                    crossave_override=bungie_fields.crossave_override,
2224                    types=bungie_fields.types,
2225                    type=bungie_fields.type,
2226                )
2227                members_.append(members_fields)
2228        else:
2229            return None
2230        return members_
2231
2232    def deserialize_available_fireteams(
2233        self,
2234        data: typedefs.JSONObject,
2235        *,
2236        no_results: bool = False,
2237    ) -> typing.Union[
2238        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2239    ]:
2240        fireteams_: list[fireteams.AvailableFireteam] = []
2241
2242        # This needs to be used outside the results
2243        # JSON key.
2244        if no_results is True:
2245            payload = data
2246
2247        if result := payload.get("results"):
2248
2249            for fireteam in result:
2250                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2251                fireteams_fields = fireteams.AvailableFireteam(
2252                    id=found_fireteams.id,
2253                    group_id=found_fireteams.group_id,
2254                    platform=found_fireteams.platform,
2255                    activity_type=found_fireteams.activity_type,
2256                    is_immediate=found_fireteams.is_immediate,
2257                    is_public=found_fireteams.is_public,
2258                    is_valid=found_fireteams.is_valid,
2259                    owner_id=found_fireteams.owner_id,
2260                    player_slot_count=found_fireteams.player_slot_count,
2261                    available_player_slots=found_fireteams.available_player_slots,
2262                    available_alternate_slots=found_fireteams.available_alternate_slots,
2263                    title=found_fireteams.title,
2264                    date_created=found_fireteams.date_created,
2265                    locale=found_fireteams.locale,
2266                    last_modified=found_fireteams.last_modified,
2267                    total_results=found_fireteams.total_results,
2268                    members=self.deserialize_fireteam_members(payload),
2269                    alternatives=self.deserialize_fireteam_members(
2270                        payload, alternatives=True
2271                    ),
2272                )
2273            fireteams_.append(fireteams_fields)
2274            if no_results:
2275                return fireteams_fields
2276        return fireteams_
2277
2278    def deserialize_fireteam_party(
2279        self, payload: typedefs.JSONObject
2280    ) -> fireteams.FireteamParty:
2281        last_destination_hash: typing.Optional[int] = None
2282        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2283            last_destination_hash = int(raw_dest_hash)
2284
2285        return fireteams.FireteamParty(
2286            members=[
2287                self._deserialize_fireteam_party_member(member)
2288                for member in payload["partyMembers"]
2289            ],
2290            activity=self._deserialize_fireteam_party_current_activity(
2291                payload["currentActivity"]
2292            ),
2293            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2294            last_destination_hash=last_destination_hash,
2295            tracking=payload["tracking"],
2296        )
2297
2298    def _deserialize_fireteam_party_member(
2299        self, payload: typedefs.JSONObject
2300    ) -> fireteams.FireteamPartyMember:
2301
2302        status = fireteams.FireteamPartyMemberState(payload["status"])
2303        displayname: undefined.UndefinedOr[str] = undefined.Undefined
2304        if raw_name := payload.get("displayName"):
2305            displayname = raw_name
2306
2307        return fireteams.FireteamPartyMember(
2308            membership_id=int(payload["membershipId"]),
2309            emblem_hash=int(payload["emblemHash"]),
2310            status=status,
2311            display_name=displayname,
2312        )
2313
2314    def _deserialize_fireteam_party_current_activity(
2315        self, payload: typedefs.JSONObject
2316    ) -> fireteams.FireteamPartyCurrentActivity:
2317        start_date: typing.Optional[datetime.datetime] = None
2318        if raw_start_date := payload.get("startTime"):
2319            start_date = time.clean_date(raw_start_date)
2320
2321        end_date: typing.Optional[datetime.datetime] = None
2322        if raw_end_date := payload.get("endTime"):
2323            end_date = time.clean_date(raw_end_date)
2324        return fireteams.FireteamPartyCurrentActivity(
2325            start_time=start_date,
2326            end_time=end_date,
2327            score=float(payload["score"]),
2328            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2329            opponenst_count=int(payload["numberOfOpponents"]),
2330            player_count=int(payload["numberOfPlayers"]),
2331        )
2332
2333    def _deserialize_fireteam_party_settings(
2334        self, payload: typedefs.JSONObject
2335    ) -> fireteams.FireteamPartySettings:
2336        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2337        return fireteams.FireteamPartySettings(
2338            open_slots=int(payload["openSlots"]),
2339            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2340            closed_reasons=closed_reasons,
2341        )
2342
2343    def deserialize_seasonal_artifact(
2344        self, payload: typedefs.JSONObject
2345    ) -> season.Artifact:
2346        if raw_artifact := payload.get("seasonalArtifact"):
2347            if points := raw_artifact.get("pointProgression"):
2348                points_prog = progressions.Progression(
2349                    hash=points["progressionHash"],
2350                    level=points["level"],
2351                    cap=points["levelCap"],
2352                    daily_limit=points["dailyLimit"],
2353                    weekly_limit=points["weeklyLimit"],
2354                    current_progress=points["currentProgress"],
2355                    daily_progress=points["dailyProgress"],
2356                    needed=points["progressToNextLevel"],
2357                    next_level=points["nextLevelAt"],
2358                )
2359
2360            if bonus := raw_artifact.get("powerBonusProgression"):
2361                power_bonus_prog = progressions.Progression(
2362                    hash=bonus["progressionHash"],
2363                    level=bonus["level"],
2364                    cap=bonus["levelCap"],
2365                    daily_limit=bonus["dailyLimit"],
2366                    weekly_limit=bonus["weeklyLimit"],
2367                    current_progress=bonus["currentProgress"],
2368                    daily_progress=bonus["dailyProgress"],
2369                    needed=bonus["progressToNextLevel"],
2370                    next_level=bonus["nextLevelAt"],
2371                )
2372            artifact = season.Artifact(
2373                net=self._net,
2374                hash=raw_artifact["artifactHash"],
2375                power_bonus=raw_artifact["powerBonus"],
2376                acquired_points=raw_artifact["pointsAcquired"],
2377                bonus=power_bonus_prog,
2378                points=points_prog,
2379            )
2380        return artifact
2381
2382    def deserialize_profile_progression(
2383        self, payload: typedefs.JSONObject
2384    ) -> profile.ProfileProgression:
2385        return profile.ProfileProgression(
2386            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2387            checklist={
2388                int(check_id): checklists
2389                for check_id, checklists in payload["data"]["checklists"].items()
2390            },
2391        )
2392
2393    def deserialize_instanced_item(
2394        self, payload: typedefs.JSONObject
2395    ) -> items.ItemInstance:
2396        damage_type_hash: typing.Optional[int] = None
2397        if raw_damagetype_hash := payload.get("damageTypeHash"):
2398            damage_type_hash = int(raw_damagetype_hash)
2399
2400        required_hashes: typing.Optional[collections.Collection[int]] = None
2401        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2402            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2403
2404        breaker_type: typing.Optional[items.ItemBreakerType] = None
2405        if raw_break_type := payload.get("breakerType"):
2406            breaker_type = items.ItemBreakerType(int(raw_break_type))
2407
2408        breaker_type_hash: typing.Optional[int] = None
2409        if raw_break_type_hash := payload.get("breakerTypeHash"):
2410            breaker_type_hash = int(raw_break_type_hash)
2411
2412        energy: typing.Optional[items.ItemEnergy] = None
2413        if raw_energy := payload.get("energy"):
2414            energy = self.deserialize_item_energy(raw_energy)
2415
2416        primary_stats = None
2417        if raw_primary_stats := payload.get("primaryStat"):
2418            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2419
2420        return items.ItemInstance(
2421            damage_type=enums.DamageType(int(payload["damageType"])),
2422            damage_type_hash=damage_type_hash,
2423            primary_stat=primary_stats,
2424            item_level=int(payload["itemLevel"]),
2425            quality=int(payload["quality"]),
2426            is_equipped=payload["isEquipped"],
2427            can_equip=payload["canEquip"],
2428            equip_required_level=int(payload["equipRequiredLevel"]),
2429            required_equip_unlock_hashes=required_hashes,
2430            cant_equip_reason=int(payload["cannotEquipReason"]),
2431            breaker_type=breaker_type,
2432            breaker_type_hash=breaker_type_hash,
2433            energy=energy,
2434        )
2435
2436    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2437        energy_hash: typing.Optional[int] = None
2438        if raw_energy_hash := payload.get("energyTypeHash"):
2439            energy_hash = int(raw_energy_hash)
2440
2441        return items.ItemEnergy(
2442            hash=energy_hash,
2443            type=items.ItemEnergyType(int(payload["energyType"])),
2444            capacity=int(payload["energyCapacity"]),
2445            used_energy=int(payload["energyUsed"]),
2446            unused_energy=int(payload["energyUnused"]),
2447        )
2448
2449    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2450        perk_hash: typing.Optional[int] = None
2451        if raw_perk_hash := payload.get("perkHash"):
2452            perk_hash = int(raw_perk_hash)
2453
2454        return items.ItemPerk(
2455            hash=perk_hash,
2456            icon=assets.Image(payload["iconPath"]),
2457            is_active=payload["isActive"],
2458            is_visible=payload["visible"],
2459        )
2460
2461    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2462        plug_hash: typing.Optional[int] = None
2463        if raw_plug_hash := payload.get("plugHash"):
2464            plug_hash = int(raw_plug_hash)
2465
2466        enable_fail_indexes: typing.Optional[list[int]] = None
2467        if raw_indexes := payload.get("enableFailIndexes"):
2468            enable_fail_indexes = [int(index) for index in raw_indexes]
2469
2470        return items.ItemSocket(
2471            plug_hash=plug_hash,
2472            is_enabled=payload["isEnabled"],
2473            enable_fail_indexes=enable_fail_indexes,
2474            is_visible=payload.get("visible"),
2475        )
2476
2477    def deserialize_item_stats_view(
2478        self, payload: typedefs.JSONObject
2479    ) -> items.ItemStatsView:
2480        return items.ItemStatsView(
2481            stat_hash=payload.get("statHash"), value=payload.get("value")
2482        )
2483
2484    def deserialize_plug_item_state(
2485        self, payload: typedefs.JSONObject
2486    ) -> items.PlugItemState:
2487        item_hash: typing.Optional[int] = None
2488        if raw_item_hash := payload.get("plugItemHash"):
2489            item_hash = int(raw_item_hash)
2490
2491        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2492        if raw_fail_indexes := payload.get("insertFailIndexes"):
2493            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2494
2495        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2496        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2497            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2498
2499        return items.PlugItemState(
2500            item_hash=item_hash,
2501            insert_fail_indexes=insert_fail_indexes,
2502            enable_fail_indexes=enable_fail_indexes,
2503            is_enabled=payload["enabled"],
2504            can_insert=payload["canInsert"],
2505        )

The base deserialization factory class for all aiobungie objects.

Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
70    def __init__(self, net: traits.Netrunner) -> None:
71        self._net = net
def deserialize_bungie_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
74        return user.BungieUser(
75            id=int(data["membershipId"]),
76            created_at=time.clean_date(data["firstAccess"]),
77            name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined),
78            is_deleted=data["isDeleted"],
79            about=data["about"],
80            updated_at=time.clean_date(data["lastUpdate"]),
81            psn_name=data.get("psnDisplayName", None),
82            stadia_name=data.get("stadiaDisplayName", None),
83            steam_name=data.get("steamDisplayName", None),
84            twitch_name=data.get("twitchDisplayName", None),
85            blizzard_name=data.get("blizzardDisplayName", None),
86            status=data["statusText"],
87            locale=data["locale"],
88            picture=assets.Image(path=str(data["profilePicturePath"])),
89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
90            unique_name=data.get("uniqueName", None),
91            theme_id=int(data["profileTheme"]),
92            show_activity=bool(data["showActivity"]),
93            theme_name=data["profileThemeName"],
94            display_title=data["userTitleDisplay"],
95        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 97    def deserialize_partial_bungie_user(
 98        self, payload: typedefs.JSONObject
 99    ) -> user.PartialBungieUser:
100        return user.PartialBungieUser(
101            net=self._net,
102            types=[
103                enums.MembershipType(type_)
104                for type_ in payload.get("applicableMembershipTypes", [])
105            ],
106            name=payload.get("displayName", undefined.Undefined),
107            id=int(payload["membershipId"]),
108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
109            is_public=payload["isPublic"],
110            icon=assets.Image(payload.get("iconPath", "")),
111            type=enums.MembershipType(payload["membershipType"]),
112        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
114    def deserialize_destiny_membership(
115        self, payload: typedefs.JSONObject
116    ) -> user.DestinyMembership:
117        name: undefined.UndefinedOr[str] = undefined.Undefined
118        if (
119            raw_name := payload.get("bungieGlobalDisplayName", "")
120        ) and not typedefs.is_unknown(raw_name):
121            name = raw_name
122
123        return user.DestinyMembership(
124            net=self._net,
125            id=int(payload["membershipId"]),
126            name=name,
127            code=payload.get("bungieGlobalDisplayNameCode", None),
128            last_seen_name=payload.get("LastSeenDisplayName")
129            or payload.get("displayName")
130            or "",
131            type=enums.MembershipType(payload["membershipType"]),
132            is_public=payload["isPublic"],
133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
134            icon=assets.Image(payload.get("iconPath", "")),
135            types=[
136                enums.MembershipType(type_)
137                for type_ in payload["applicableMembershipTypes"]
138                if "applicableMembershipTypes" in payload
139            ],
140        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
142    def deserialize_destiny_memberships(
143        self, data: typedefs.JSONArray
144    ) -> collections.Sequence[user.DestinyMembership]:
145        return [self.deserialize_destiny_membership(membership) for membership in data]

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.User:
147    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
148
149        primary_membership_id: typing.Optional[int] = None
150        if raw_primary_id := data.get("primaryMembershipId"):
151            primary_membership_id = int(raw_primary_id)
152
153        return user.User(
154            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
155            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
156            primary_membership_id=primary_membership_id,
157        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
159    def deserialize_searched_user(
160        self, payload: typedefs.JSONObject
161    ) -> user.SearchableDestinyUser:
162        name: undefined.UndefinedOr[str] = undefined.Undefined
163        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
164            raw_name
165        ):
166            name = raw_name
167
168        code: typing.Optional[int] = None
169        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
170            code = int(raw_code)
171
172        bungie_id: typing.Optional[int] = None
173        if raw_bungie_id := payload.get("bungieNetMembershipId"):
174            bungie_id = int(raw_bungie_id)
175
176        return user.SearchableDestinyUser(
177            name=name,
178            code=code,
179            bungie_id=bungie_id,
180            memberships=self.deserialize_destiny_memberships(
181                payload["destinyMemberships"]
182            ),
183        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
185    def deserialize_user_credentials(
186        self, payload: typedefs.JSONArray
187    ) -> collections.Sequence[user.UserCredentials]:
188        return [
189            user.UserCredentials(
190                type=enums.CredentialType(int(creds["credentialType"])),
191                display_name=creds["credentialDisplayName"],
192                is_public=creds["isPublic"],
193                self_as_string=creds.get("credentialAsString", undefined.Undefined),
194            )
195            for creds in payload
196        ]

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
@staticmethod
def set_themese_attrs( payload: list[typing.Any], /) -> Collection[aiobungie.crates.user.UserThemes]:
198    @staticmethod
199    def set_themese_attrs(
200        payload: typedefs.JSONArray, /
201    ) -> typing.Collection[user.UserThemes]:
202        return [
203            user.UserThemes(
204                id=int(entry["userThemeId"]),
205                name=entry["userThemeName"]
206                if "userThemeName" in entry
207                else undefined.Undefined,
208                description=entry["userThemeDescription"]
209                if "userThemeDescription" in entry
210                else undefined.Undefined,
211            )
212            for entry in payload
213        ]
def deserialize_user_themes( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
215    def deserialize_user_themes(
216        self, payload: typedefs.JSONArray
217    ) -> collections.Sequence[user.UserThemes]:
218        return list(self.set_themese_attrs(payload))

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan(self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.Clan:
220    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
221
222        # This is kinda redundant
223        data = payload
224
225        # This is always outside the details.
226        current_user_map: typing.Optional[
227            collections.Mapping[str, clans.ClanMember]
228        ] = None
229        if raw_current_user_map := payload.get("currentUserMemberMap"):
230            current_user_map = {
231                membership_type: self.deserialize_clan_member(membership)
232                for membership_type, membership in raw_current_user_map.items()
233            }
234
235        try:
236            data = payload["detail"]
237        except KeyError:
238            pass
239
240        id = data["groupId"]
241        name = data["name"]
242        created_at = data["creationDate"]
243        member_count = data["memberCount"]
244        about = data["about"]
245        motto = data["motto"]
246        is_public = data["isPublic"]
247        banner = assets.Image(str(data["bannerPath"]))
248        avatar = assets.Image(str(data["avatarPath"]))
249        tags = data["tags"]
250        type = data["groupType"]
251
252        features = data["features"]
253        features_obj = clans.ClanFeatures(
254            max_members=features["maximumMembers"],
255            max_membership_types=features["maximumMembershipsOfGroupType"],
256            capabilities=features["capabilities"],
257            membership_types=features["membershipTypes"],
258            invite_permissions=features["invitePermissionOverride"],
259            update_banner_permissions=features["updateBannerPermissionOverride"],
260            update_culture_permissions=features["updateCulturePermissionOverride"],
261            join_level=features["joinLevel"],
262        )
263
264        information: typedefs.JSONObject = data["clanInfo"]
265        progression: collections.Mapping[int, progressions.Progression] = {
266            int(prog_hash): self.deserialize_progressions(prog)
267            for prog_hash, prog in information["d2ClanProgressions"].items()
268        }
269
270        founder: typedefs.NoneOr[clans.ClanMember] = None
271        if raw_founder := payload.get("founder"):
272            founder = self.deserialize_clan_member(raw_founder)
273
274        return clans.Clan(
275            net=self._net,
276            id=int(id),
277            name=name,
278            type=enums.GroupType(type),
279            created_at=time.clean_date(created_at),
280            member_count=member_count,
281            motto=motto,
282            about=about,
283            is_public=is_public,
284            banner=banner,
285            avatar=avatar,
286            tags=tags,
287            features=features_obj,
288            owner=founder,
289            progressions=progression,
290            call_sign=information["clanCallsign"],
291            banner_data=information["clanBannerData"],
292            chat_security=data["chatSecurity"],
293            conversation_id=int(data["conversationId"]),
294            allow_chat=data["allowChat"],
295            theme=data["theme"],
296            current_user_membership=current_user_map,
297        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: dict[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
299    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
300        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
301        return clans.ClanMember(
302            net=self._net,
303            last_seen_name=destiny_user.last_seen_name,
304            id=destiny_user.id,
305            name=destiny_user.name,
306            icon=destiny_user.icon,
307            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
308            group_id=int(data["groupId"]),
309            joined_at=time.clean_date(data["joinDate"]),
310            types=destiny_user.types,
311            is_public=destiny_user.is_public,
312            type=destiny_user.type,
313            code=destiny_user.code,
314            is_online=data["isOnline"],
315            crossave_override=destiny_user.crossave_override,
316            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
317            if "bungieNetUserInfo" in data
318            else None,
319            member_type=enums.ClanMemberType(int(data["memberType"])),
320        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: dict[str, typing.Any], /) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
322    def deserialize_clan_members(
323        self, data: typedefs.JSONObject, /
324    ) -> iterators.FlatIterator[clans.ClanMember]:
325        return iterators.FlatIterator(
326            [self.deserialize_clan_member(member) for member in data["results"]]
327        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
329    def deserialize_group_member(
330        self, payload: typedefs.JSONObject
331    ) -> clans.GroupMember:
332        member = payload["member"]
333        return clans.GroupMember(
334            net=self._net,
335            join_date=time.clean_date(member["joinDate"]),
336            group_id=int(member["groupId"]),
337            member_type=enums.ClanMemberType(member["memberType"]),
338            is_online=member["isOnline"],
339            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
340            inactive_memberships=payload.get("areAllMembershipsInactive", None),
341            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
342            group=self.deserialize_clan(payload["group"]),
343        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
361    def deserialize_clan_conversations(
362        self, payload: typedefs.JSONArray
363    ) -> collections.Sequence[clans.ClanConversation]:
364        return [self._deserialize_clan_conversation(conv) for conv in payload]

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
366    def deserialize_app_owner(
367        self, payload: typedefs.JSONObject
368    ) -> application.ApplicationOwner:
369        return application.ApplicationOwner(
370            net=self._net,
371            name=payload.get("bungieGlobalDisplayName", undefined.Undefined),
372            id=int(payload["membershipId"]),
373            type=enums.MembershipType(payload["membershipType"]),
374            icon=assets.Image(str(payload["iconPath"])),
375            is_public=payload["isPublic"],
376            code=payload.get("bungieGlobalDisplayNameCode", None),
377        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.Application:
379    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
380        return application.Application(
381            id=int(payload["applicationId"]),
382            name=payload["name"],
383            link=payload["link"],
384            status=payload["status"],
385            redirect_url=payload.get("redirectUrl", None),
386            created_at=time.clean_date(str(payload["creationDate"])),
387            published_at=time.clean_date(str(payload["firstPublished"])),
388            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
389            scope=payload.get("scope", undefined.Undefined),
390        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: dict[str, typing.Any], /) -> Optional[aiobungie.crates.profile.Profile]:
413    def deserialize_profile(
414        self, payload: typedefs.JSONObject, /
415    ) -> typing.Optional[profile.Profile]:
416        if (raw_profile := payload.get("data")) is None:
417            return None
418
419        payload = raw_profile
420        id = int(payload["userInfo"]["membershipId"])
421        name = payload["userInfo"]["displayName"]
422        is_public = payload["userInfo"]["isPublic"]
423        type = enums.MembershipType(payload["userInfo"]["membershipType"])
424        last_played = time.clean_date(str(payload["dateLastPlayed"]))
425        character_ids = [int(cid) for cid in payload["characterIds"]]
426        power_cap = payload["currentSeasonRewardPowerCap"]
427
428        return profile.Profile(
429            id=int(id),
430            name=name,
431            is_public=is_public,
432            type=type,
433            last_played=last_played,
434            character_ids=character_ids,
435            power_cap=power_cap,
436            net=self._net,
437        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
439    def deserialize_profile_item(
440        self, payload: typedefs.JSONObject
441    ) -> profile.ProfileItemImpl:
442
443        instance_id: typing.Optional[int] = None
444        if raw_instance_id := payload.get("itemInstanceId"):
445            instance_id = int(raw_instance_id)
446
447        version_number: typing.Optional[int] = None
448        if raw_version := payload.get("versionNumber"):
449            version_number = int(raw_version)
450
451        transfer_status = enums.TransferStatus(payload["transferStatus"])
452
453        return profile.ProfileItemImpl(
454            net=self._net,
455            hash=payload["itemHash"],
456            quantity=payload["quantity"],
457            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
458            location=enums.ItemLocation(payload["location"]),
459            bucket=payload["bucketHash"],
460            transfer_status=transfer_status,
461            lockable=payload["lockable"],
462            state=enums.ItemState(payload["state"]),
463            dismantel_permissions=payload["dismantlePermission"],
464            is_wrapper=payload["isWrapper"],
465            instance_id=instance_id,
466            version_number=version_number,
467            ornament_id=payload.get("overrideStyleItemHash"),
468        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: dict[str, typing.Any]) -> aiobungie.crates.records.Objective:
470    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
471        return records.Objective(
472            net=self._net,
473            hash=payload["objectiveHash"],
474            visible=payload["visible"],
475            complete=payload["complete"],
476            completion_value=payload["completionValue"],
477            progress=payload.get("progress"),
478            destination_hash=payload.get("destinationHash"),
479            activity_hash=payload.get("activityHash"),
480        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, **nodes: int) -> aiobungie.crates.records.Record:
482    def deserialize_records(
483        self,
484        payload: typedefs.JSONObject,
485        scores: typing.Optional[records.RecordScores] = None,
486        **nodes: int,
487    ) -> records.Record:
488        objectives: typing.Optional[list[records.Objective]] = None
489        interval_objectives: typing.Optional[list[records.Objective]] = None
490        record_state: typedefs.IntAnd[records.RecordState]
491
492        record_state = records.RecordState(payload["state"])
493
494        if raw_objs := payload.get("objectives"):
495            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
496
497        if raw_interval_objs := payload.get("intervalObjectives"):
498            interval_objectives = [
499                self.deserialize_objectives(obj) for obj in raw_interval_objs
500            ]
501
502        return records.Record(
503            scores=scores,
504            categories_node_hash=nodes.get("categories_hash", undefined.Undefined),
505            seals_node_hash=nodes.get("seals_hash", undefined.Undefined),
506            state=record_state,
507            objectives=objectives,
508            interval_objectives=interval_objectives,
509            redeemed_count=payload.get("intervalsRedeemedCount", 0),
510            completion_times=payload.get("completedCount", None),
511            reward_visibility=payload.get("rewardVisibilty", None),
512        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, record_hashes: Optional[list[int]] = None) -> aiobungie.crates.records.CharacterRecord:
514    def deserialize_character_records(
515        self,
516        payload: typedefs.JSONObject,
517        scores: typing.Optional[records.RecordScores] = None,
518        record_hashes: typing.Optional[list[int]] = None,
519    ) -> records.CharacterRecord:
520
521        record = self.deserialize_records(payload, scores)
522        return records.CharacterRecord(
523            scores=scores,
524            categories_node_hash=record.categories_node_hash,
525            seals_node_hash=record.seals_node_hash,
526            state=record.state,
527            objectives=record.objectives,
528            interval_objectives=record.interval_objectives,
529            redeemed_count=payload.get("intervalsRedeemedCount", 0),
530            completion_times=payload.get("completedCount"),
531            reward_visibility=payload.get("rewardVisibilty"),
532            record_hashes=record_hashes or [],
533        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye(self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Dye:
535    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
536        return character.Dye(
537            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
538        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
540    def deserialize_character_customization(
541        self, payload: typedefs.JSONObject
542    ) -> character.CustomizationOptions:
543        return character.CustomizationOptions(
544            personality=payload["personality"],
545            face=payload["face"],
546            skin_color=payload["skinColor"],
547            lip_color=payload["lipColor"],
548            eye_color=payload["eyeColor"],
549            hair_colors=payload.get("hairColors", []),
550            feature_colors=payload.get("featureColors", []),
551            decal_color=payload["decalColor"],
552            wear_helmet=payload["wearHelmet"],
553            hair_index=payload["hairIndex"],
554            feature_index=payload["featureIndex"],
555            decal_index=payload["decalIndex"],
556        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
558    def deserialize_character_minimal_equipments(
559        self, payload: typedefs.JSONObject
560    ) -> character.MinimalEquipments:
561        dyes = None
562        if raw_dyes := payload.get("dyes"):
563            if raw_dyes:
564                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
565        return character.MinimalEquipments(
566            net=self._net, item_hash=payload["itemHash"], dyes=dyes
567        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
569    def deserialize_character_render_data(
570        self, payload: typedefs.JSONObject, /
571    ) -> character.RenderedData:
572        return character.RenderedData(
573            net=self._net,
574            customization=self.deserialize_character_customization(
575                payload["customization"]
576            ),
577            custom_dyes=[
578                self.deserialize_character_dye(dye)
579                for dye in payload["customDyes"]
580                if dye
581            ],
582            equipment=[
583                self.deserialize_character_minimal_equipments(equipment)
584                for equipment in payload["peerView"]["equipment"]
585            ],
586        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
588    def deserialize_available_activity(
589        self, payload: typedefs.JSONObject
590    ) -> activity.AvailableActivity:
591        return activity.AvailableActivity(
592            hash=payload["activityHash"],
593            is_new=payload["isNew"],
594            is_completed=payload["isCompleted"],
595            is_visible=payload["isVisible"],
596            display_level=payload.get("displayLevel"),
597            recommended_light=payload.get("recommendedLight"),
598            difficulty=activity.Difficulty(payload["difficultyTier"]),
599            can_join=payload["canJoin"],
600            can_lead=payload["canLead"],
601        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
603    def deserialize_character_activity(
604        self, payload: typedefs.JSONObject
605    ) -> activity.CharacterActivity:
606        current_mode: typing.Optional[enums.GameMode] = None
607        if raw_current_mode := payload.get("currentActivityModeType"):
608            current_mode = enums.GameMode(raw_current_mode)
609
610        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
611        if raw_current_modes := payload.get("currentActivityModeTypes"):
612            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
613
614        return activity.CharacterActivity(
615            date_started=time.clean_date(payload["dateActivityStarted"]),
616            current_hash=payload["currentActivityHash"],
617            current_mode_hash=payload["currentActivityModeHash"],
618            current_mode=current_mode,
619            current_mode_hashes=payload.get("currentActivityModeHashes"),
620            current_mode_types=current_mode_types,
621            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
622            last_story_hash=payload["lastCompletedStoryHash"],
623            available_activities=[
624                self.deserialize_available_activity(activity_)
625                for activity_ in payload["availableActivities"]
626            ],
627        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: dict[str, typing.Any], /) -> list[aiobungie.crates.profile.ProfileItemImpl]:
629    def deserialize_profile_items(
630        self, payload: typedefs.JSONObject, /
631    ) -> list[profile.ProfileItemImpl]:
632        return [self.deserialize_profile_item(item) for item in payload["items"]]

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
675    def deserialize_progressions(
676        self, payload: typedefs.JSONObject
677    ) -> progressions.Progression:
678        return progressions.Progression(
679            hash=int(payload["progressionHash"]),
680            level=int(payload["level"]),
681            cap=int(payload["levelCap"]),
682            daily_limit=int(payload["dailyLimit"]),
683            weekly_limit=int(payload["weeklyLimit"]),
684            current_progress=int(payload["currentProgress"]),
685            daily_progress=int(payload["dailyProgress"]),
686            needed=int(payload["progressToNextLevel"]),
687            next_level=int(payload["nextLevelAt"]),
688        )
def deserialize_milestone( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
776    def deserialize_milestone(
777        self, payload: typedefs.JSONObject
778    ) -> milestones.Milestone:
779        start_date: typing.Optional[datetime.datetime] = None
780        if raw_start_date := payload.get("startDate"):
781            start_date = time.clean_date(raw_start_date)
782
783        end_date: typing.Optional[datetime.datetime] = None
784        if raw_end_date := payload.get("endDate"):
785            end_date = time.clean_date(raw_end_date)
786
787        rewards: typing.Optional[
788            collections.Collection[milestones.MilestoneReward]
789        ] = None
790        if raw_rewards := payload.get("rewards"):
791            rewards = [
792                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
793            ]
794
795        activities: typing.Optional[
796            collections.Sequence[milestones.MilestoneActivity]
797        ] = None
798        if raw_activities := payload.get("activities"):
799            activities = [
800                self._deserialize_milestone_activity(active)
801                for active in raw_activities
802            ]
803
804        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
805        if raw_quests := payload.get("availableQuests"):
806            quests = [
807                self._deserialize_milestone_available_quest(quest)
808                for quest in raw_quests
809            ]
810
811        vendors: typing.Optional[
812            collections.Sequence[milestones.MilestoneVendor]
813        ] = None
814        if raw_vendors := payload.get("vendors"):
815            vendors = [
816                milestones.MilestoneVendor(
817                    vendor_hash=vendor["vendorHash"],
818                    preview_itemhash=vendor.get("previewItemHash"),
819                )
820                for vendor in raw_vendors
821            ]
822
823        return milestones.Milestone(
824            hash=payload["milestoneHash"],
825            start_date=start_date,
826            end_date=end_date,
827            order=payload["order"],
828            rewards=rewards,
829            available_quests=quests,
830            activities=activities,
831            vendors=vendors,
832        )
def deserialize_characters( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
849    def deserialize_characters(
850        self, payload: typedefs.JSONObject
851    ) -> collections.Mapping[int, character.Character]:
852        return {
853            int(char_id): self._set_character_attrs(char)
854            for char_id, char in payload["data"].items()
855        }
def deserialize_character( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Character:
857    def deserialize_character(
858        self, payload: typedefs.JSONObject
859    ) -> character.Character:
860        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
862    def deserialize_character_equipments(
863        self, payload: typedefs.JSONObject
864    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
865        return {
866            int(char_id): self.deserialize_profile_items(item)
867            for char_id, item in payload["data"].items()
868        }
def deserialize_character_activities( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
870    def deserialize_character_activities(
871        self, payload: typedefs.JSONObject
872    ) -> collections.Mapping[int, activity.CharacterActivity]:
873        return {
874            int(char_id): self.deserialize_character_activity(data)
875            for char_id, data in payload["data"].items()
876        }
def deserialize_characters_render_data( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
878    def deserialize_characters_render_data(
879        self, payload: typedefs.JSONObject
880    ) -> collections.Mapping[int, character.RenderedData]:
881        return {
882            int(char_id): self.deserialize_character_render_data(data)
883            for char_id, data in payload["data"].items()
884        }
def deserialize_character_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
886    def deserialize_character_progressions(
887        self, payload: typedefs.JSONObject
888    ) -> character.CharacterProgression:
889        progressions_ = {
890            int(prog_id): self.deserialize_progressions(prog)
891            for prog_id, prog in payload["progressions"].items()
892        }
893
894        factions = {
895            int(faction_id): self._deserialize_factions(faction)
896            for faction_id, faction in payload["factions"].items()
897        }
898
899        milestones_ = {
900            int(milestone_hash): self.deserialize_milestone(milestone)
901            for milestone_hash, milestone in payload["milestones"].items()
902        }
903
904        uninstanced_item_objectives = {
905            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
906            for item_hash, obj in payload["uninstancedItemObjectives"].items()
907        }
908
909        artifact = payload["seasonalArtifact"]
910        seasonal_artifact = season.CharacterScopedArtifact(
911            hash=artifact["artifactHash"],
912            points_used=artifact["pointsUsed"],
913            reset_count=artifact["resetCount"],
914            tiers=[
915                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
916            ],
917        )
918        checklists = payload["checklists"]
919
920        return character.CharacterProgression(
921            progressions=progressions_,
922            factions=factions,
923            checklists=checklists,
924            milestones=milestones_,
925            seasonal_artifact=seasonal_artifact,
926            uninstanced_item_objectives=uninstanced_item_objectives,
927        )
def deserialize_character_progressions_mapping( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
929    def deserialize_character_progressions_mapping(
930        self, payload: typedefs.JSONObject
931    ) -> collections.Mapping[int, character.CharacterProgression]:
932        character_progressions: collections.Mapping[
933            int, character.CharacterProgression
934        ] = {}
935        for char_id, data in payload["data"].items():
936            # A little hack to stop mypy complaining about Mapping <-> dict
937            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
938        return character_progressions
def deserialize_characters_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
940    def deserialize_characters_records(
941        self,
942        payload: typedefs.JSONObject,
943    ) -> collections.Mapping[int, records.CharacterRecord]:
944
945        return {
946            int(rec_id): self.deserialize_character_records(
947                rec, record_hashes=payload.get("featuredRecordHashes")
948            )
949            for rec_id, rec in payload["records"].items()
950        }
def deserialize_profile_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
952    def deserialize_profile_records(
953        self, payload: typedefs.JSONObject
954    ) -> collections.Mapping[int, records.Record]:
955        raw_profile_records = payload["data"]
956        scores = records.RecordScores(
957            current_score=raw_profile_records["score"],
958            legacy_score=raw_profile_records["legacyScore"],
959            lifetime_score=raw_profile_records["lifetimeScore"],
960        )
961        return {
962            int(record_id): self.deserialize_records(
963                record,
964                scores,
965                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
966                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
967            )
968            for record_id, record in raw_profile_records["records"].items()
969        }
def deserialize_craftables_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
1006    def deserialize_craftables_component(
1007        self, payload: typedefs.JSONObject
1008    ) -> components.CraftablesComponent:
1009        return components.CraftablesComponent(
1010            net=self._net,
1011            craftables={
1012                int(item_id): self._deserialize_craftable_item(item)
1013                for item_id, item in payload["craftables"].items()
1014                if item is not None
1015            },
1016            crafting_root_node_hash=payload["craftingRootNodeHash"],
1017        )
def deserialize_components( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.Component:
1019    def deserialize_components(  # noqa: C901 Too complex.
1020        self, payload: typedefs.JSONObject
1021    ) -> components.Component:
1022
1023        profile_: typing.Optional[profile.Profile] = None
1024        if raw_profile := payload.get("profile"):
1025            profile_ = self.deserialize_profile(raw_profile)
1026
1027        profile_progression: typing.Optional[profile.ProfileProgression] = None
1028        if raw_profile_progression := payload.get("profileProgression"):
1029            profile_progression = self.deserialize_profile_progression(
1030                raw_profile_progression
1031            )
1032
1033        profile_currencies: typing.Optional[
1034            collections.Sequence[profile.ProfileItemImpl]
1035        ] = None
1036        if raw_profile_currencies := payload.get("profileCurrencies"):
1037            if "data" in raw_profile_currencies:
1038                profile_currencies = self.deserialize_profile_items(
1039                    raw_profile_currencies["data"]
1040                )
1041
1042        profile_inventories: typing.Optional[
1043            collections.Sequence[profile.ProfileItemImpl]
1044        ] = None
1045        if raw_profile_inventories := payload.get("profileInventory"):
1046            if "data" in raw_profile_inventories:
1047                profile_inventories = self.deserialize_profile_items(
1048                    raw_profile_inventories["data"]
1049                )
1050
1051        profile_records: typing.Optional[
1052            collections.Mapping[int, records.Record]
1053        ] = None
1054
1055        if raw_profile_records_ := payload.get("profileRecords"):
1056            profile_records = self.deserialize_profile_records(raw_profile_records_)
1057
1058        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1059        if raw_characters := payload.get("characters"):
1060            characters = self.deserialize_characters(raw_characters)
1061
1062        character_records: typing.Optional[
1063            collections.Mapping[int, records.CharacterRecord]
1064        ] = None
1065
1066        if raw_character_records := payload.get("characterRecords"):
1067            # Had to do it in two steps..
1068            to_update: typedefs.JSONObject = {}
1069            for _, data in raw_character_records["data"].items():
1070                for record_id, record in data.items():
1071                    to_update[record_id] = record
1072
1073            character_records = {
1074                int(rec_id): self.deserialize_character_records(
1075                    rec, record_hashes=to_update.get("featuredRecordHashes")
1076                )
1077                for rec_id, rec in to_update["records"].items()
1078            }
1079
1080        character_equipments: typing.Optional[
1081            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1082        ] = None
1083        if raw_character_equips := payload.get("characterEquipment"):
1084            character_equipments = self.deserialize_character_equipments(
1085                raw_character_equips
1086            )
1087
1088        character_inventories: typing.Optional[
1089            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1090        ] = None
1091        if raw_character_inventories := payload.get("characterInventories"):
1092            if "data" in raw_character_inventories:
1093                character_inventories = self.deserialize_character_equipments(
1094                    raw_character_inventories
1095                )
1096
1097        character_activities: typing.Optional[
1098            collections.Mapping[int, activity.CharacterActivity]
1099        ] = None
1100        if raw_char_acts := payload.get("characterActivities"):
1101            character_activities = self.deserialize_character_activities(raw_char_acts)
1102
1103        character_render_data: typing.Optional[
1104            collections.Mapping[int, character.RenderedData]
1105        ] = None
1106        if raw_character_render_data := payload.get("characterRenderData"):
1107            character_render_data = self.deserialize_characters_render_data(
1108                raw_character_render_data
1109            )
1110
1111        character_progressions: typing.Optional[
1112            collections.Mapping[int, character.CharacterProgression]
1113        ] = None
1114
1115        if raw_character_progressions := payload.get("characterProgressions"):
1116            character_progressions = self.deserialize_character_progressions_mapping(
1117                raw_character_progressions
1118            )
1119
1120        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1121        if raw_profile_string_vars := payload.get("profileStringVariables"):
1122            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1123
1124        character_string_vars: typing.Optional[
1125            collections.Mapping[int, collections.Mapping[int, int]]
1126        ] = None
1127        if raw_character_string_vars := payload.get("characterStringVariables"):
1128            character_string_vars = {
1129                int(char_id): data["integerValuesByHash"]
1130                for char_id, data in raw_character_string_vars["data"].items()
1131            }
1132
1133        metrics: typing.Optional[
1134            collections.Sequence[
1135                collections.Mapping[
1136                    int, tuple[bool, typing.Optional[records.Objective]]
1137                ]
1138            ]
1139        ] = None
1140        root_node_hash: typing.Optional[int] = None
1141
1142        if raw_metrics := payload.get("metrics"):
1143            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1144            metrics = [
1145                {
1146                    int(metrics_hash): (
1147                        data["invisible"],
1148                        self.deserialize_objectives(data["objectiveProgress"])
1149                        if "objectiveProgress" in data
1150                        else None,
1151                    )
1152                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1153                }
1154            ]
1155        transitory: typing.Optional[fireteams.FireteamParty] = None
1156        if raw_transitory := payload.get("profileTransitoryData"):
1157            if "data" in raw_transitory:
1158                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1159
1160        item_components: typing.Optional[components.ItemsComponent] = None
1161        if raw_item_components := payload.get("itemComponents"):
1162            item_components = self.deserialize_items_component(raw_item_components)
1163
1164        profile_plugsets: typing.Optional[
1165            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1166        ] = None
1167
1168        if raw_profile_plugs := payload.get("profilePlugSets"):
1169            profile_plugsets = {
1170                int(index): [self.deserialize_plug_item_state(state) for state in data]
1171                for index, data in raw_profile_plugs["data"]["plugs"].items()
1172            }
1173
1174        character_plugsets: typing.Optional[
1175            collections.Mapping[
1176                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1177            ]
1178        ] = None
1179        if raw_char_plugsets := payload.get("characterPlugSets"):
1180            character_plugsets = {
1181                int(char_id): {
1182                    int(index): [
1183                        self.deserialize_plug_item_state(state) for state in data
1184                    ]
1185                    for index, data in inner["plugs"].items()
1186                }
1187                for char_id, inner in raw_char_plugsets["data"].items()
1188            }
1189
1190        character_collectibles: typing.Optional[
1191            collections.Mapping[int, items.Collectible]
1192        ] = None
1193        if raw_character_collectibles := payload.get("characterCollectibles"):
1194            character_collectibles = {
1195                int(char_id): self._deserialize_collectible(data)
1196                for char_id, data in raw_character_collectibles["data"].items()
1197            }
1198
1199        profile_collectibles: typing.Optional[items.Collectible] = None
1200        if raw_profile_collectibles := payload.get("profileCollectibles"):
1201            profile_collectibles = self._deserialize_collectible(
1202                raw_profile_collectibles["data"]
1203            )
1204
1205        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1206        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1207            profile_nodes = {
1208                int(node_hash): self._deserialize_node(node)
1209                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1210            }
1211
1212        character_nodes: typing.Optional[
1213            collections.Mapping[int, collections.Mapping[int, records.Node]]
1214        ] = None
1215        if raw_character_nodes := payload.get("characterPresentationNodes"):
1216            character_nodes = {
1217                int(char_id): {
1218                    int(node_hash): self._deserialize_node(node)
1219                    for node_hash, node in each_character["nodes"].items()
1220                }
1221                for char_id, each_character in raw_character_nodes["data"].items()
1222            }
1223
1224        platform_silver: typing.Optional[
1225            collections.Mapping[str, profile.ProfileItemImpl]
1226        ] = None
1227        if raw_platform_silver := payload.get("platformSilver"):
1228            if "data" in raw_platform_silver:
1229                platform_silver = {
1230                    platform_name: self.deserialize_profile_item(item)
1231                    for platform_name, item in raw_platform_silver["data"][
1232                        "platformSilver"
1233                    ].items()
1234                }
1235
1236        character_currency_lookups: typing.Optional[
1237            collections.Mapping[int, collections.Sequence[items.Currency]]
1238        ] = None
1239        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1240            if "data" in raw_char_lookups:
1241                character_currency_lookups = {
1242                    int(char_id): self._deserialize_currencies(currencie)
1243                    for char_id, currencie in raw_char_lookups["data"].items()
1244                }
1245
1246        character_craftables: typing.Optional[
1247            collections.Mapping[int, components.CraftablesComponent]
1248        ] = None
1249        if raw_character_craftables := payload.get("characterCraftables"):
1250
1251            if "data" in raw_character_craftables:
1252                character_craftables = {
1253                    int(char_id): self.deserialize_craftables_component(craftable)
1254                    for char_id, craftable in raw_character_craftables["data"].items()
1255                }
1256
1257        return components.Component(
1258            profiles=profile_,
1259            profile_progression=profile_progression,
1260            profile_currencies=profile_currencies,
1261            profile_inventories=profile_inventories,
1262            profile_records=profile_records,
1263            characters=characters,
1264            character_records=character_records,
1265            character_equipments=character_equipments,
1266            character_inventories=character_inventories,
1267            character_activities=character_activities,
1268            character_render_data=character_render_data,
1269            character_progressions=character_progressions,
1270            profile_string_variables=profile_string_vars,
1271            character_string_variables=character_string_vars,
1272            metrics=metrics,
1273            root_node_hash=root_node_hash,
1274            transitory=transitory,
1275            item_components=item_components,
1276            profile_plugsets=profile_plugsets,
1277            character_plugsets=character_plugsets,
1278            character_collectibles=character_collectibles,
1279            profile_collectibles=profile_collectibles,
1280            profile_nodes=profile_nodes,
1281            character_nodes=character_nodes,
1282            platform_silver=platform_silver,
1283            character_currency_lookups=character_currency_lookups,
1284            character_craftables=character_craftables,
1285        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1287    def deserialize_items_component(
1288        self, payload: typedefs.JSONObject
1289    ) -> components.ItemsComponent:
1290        instances: typing.Optional[
1291            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1292        ] = None
1293        if raw_instances := payload.get("instances"):
1294            instances = [
1295                {
1296                    int(ins_id): self.deserialize_instanced_item(item)
1297                    for ins_id, item in raw_instances["data"].items()
1298                }
1299            ]
1300
1301        render_data: typing.Optional[
1302            collections.Mapping[int, tuple[bool, dict[int, int]]]
1303        ] = None
1304        if raw_render_data := payload.get("renderData"):
1305            render_data = {
1306                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1307                for ins_id, data in raw_render_data["data"].items()
1308            }
1309
1310        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1311        if raw_stats := payload.get("stats"):
1312            builder: collections.Mapping[int, items.ItemStatsView] = {}
1313            for ins_id, stat in raw_stats["data"].items():
1314                for _, items_ in stat.items():
1315                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1316            stats = builder
1317
1318        sockets: typing.Optional[
1319            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1320        ] = None
1321        if raw_sockets := payload.get("sockets"):
1322            sockets = {
1323                int(ins_id): [
1324                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1325                ]
1326                for ins_id, item in raw_sockets["data"].items()
1327            }
1328
1329        objeectives: typing.Optional[
1330            collections.Mapping[int, collections.Sequence[records.Objective]]
1331        ] = None
1332        if raw_objectives := payload.get("objectives"):
1333            objeectives = {
1334                int(ins_id): [self.deserialize_objectives(objective)]
1335                for ins_id, data in raw_objectives["data"].items()
1336                for objective in data["objectives"]
1337            }
1338
1339        perks: typing.Optional[
1340            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1341        ] = None
1342        if raw_perks := payload.get("perks"):
1343            perks = {
1344                int(ins_id): [
1345                    self.deserialize_item_perk(perk) for perk in item["perks"]
1346                ]
1347                for ins_id, item in raw_perks["data"].items()
1348            }
1349
1350        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1351        if raw_plug_states := payload.get("plugStates"):
1352            pending_states: list[items.PlugItemState] = []
1353            for _, plug in raw_plug_states["data"].items():
1354                pending_states.append(self.deserialize_plug_item_state(plug))
1355            plug_states = pending_states
1356
1357        reusable_plugs: typing.Optional[
1358            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1359        ] = None
1360        if raw_re_plugs := payload.get("reusablePlugs"):
1361            reusable_plugs = {
1362                int(ins_id): [
1363                    self.deserialize_plug_item_state(state) for state in inner
1364                ]
1365                for ins_id, plug in raw_re_plugs["data"].items()
1366                for inner in list(plug["plugs"].values())
1367            }
1368
1369        plug_objectives: typing.Optional[
1370            collections.Mapping[
1371                int, collections.Mapping[int, collections.Collection[records.Objective]]
1372            ]
1373        ] = None
1374        if raw_plug_objectives := payload.get("plugObjectives"):
1375            plug_objectives = {
1376                int(ins_id): {
1377                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1378                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1379                }
1380                for ins_id, inner in raw_plug_objectives["data"].items()
1381            }
1382
1383        return components.ItemsComponent(
1384            sockets=sockets,
1385            stats=stats,
1386            render_data=render_data,
1387            instances=instances,
1388            objectives=objeectives,
1389            perks=perks,
1390            plug_states=plug_states,
1391            reusable_plugs=reusable_plugs,
1392            plug_objectives=plug_objectives,
1393        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1395    def deserialize_character_component(  # type: ignore[call-arg]
1396        self, payload: typedefs.JSONObject
1397    ) -> components.CharacterComponent:
1398
1399        character_: typing.Optional[character.Character] = None
1400        if raw_singuler_character := payload.get("character"):
1401            character_ = self.deserialize_character(raw_singuler_character["data"])
1402
1403        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1404        if raw_inventory := payload.get("inventory"):
1405            if "data" in raw_inventory:
1406                inventory = self.deserialize_profile_items(raw_inventory["data"])
1407
1408        activities: typing.Optional[activity.CharacterActivity] = None
1409        if raw_activities := payload.get("activities"):
1410            activities = self.deserialize_character_activity(raw_activities["data"])
1411
1412        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1413        if raw_equipments := payload.get("equipment"):
1414            equipment = self.deserialize_profile_items(raw_equipments["data"])
1415
1416        progressions_: typing.Optional[character.CharacterProgression] = None
1417        if raw_progressions := payload.get("progressions"):
1418            progressions_ = self.deserialize_character_progressions(
1419                raw_progressions["data"]
1420            )
1421
1422        render_data: typing.Optional[character.RenderedData] = None
1423        if raw_render_data := payload.get("renderData"):
1424            render_data = self.deserialize_character_render_data(
1425                raw_render_data["data"]
1426            )
1427
1428        character_records: typing.Optional[
1429            collections.Mapping[int, records.CharacterRecord]
1430        ] = None
1431        if raw_char_records := payload.get("records"):
1432            character_records = self.deserialize_characters_records(
1433                raw_char_records["data"]
1434            )
1435
1436        item_components: typing.Optional[components.ItemsComponent] = None
1437        if raw_item_components := payload.get("itemComponents"):
1438            item_components = self.deserialize_items_component(raw_item_components)
1439
1440        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1441        if raw_nodes := payload.get("presentationNodes"):
1442            nodes = {
1443                int(node_hash): self._deserialize_node(node)
1444                for node_hash, node in raw_nodes["data"]["nodes"].items()
1445            }
1446
1447        collectibles: typing.Optional[items.Collectible] = None
1448        if raw_collectibles := payload.get("collectibles"):
1449            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1450
1451        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1452        if raw_currencies := payload.get("currencyLookups"):
1453            if "data" in raw_currencies:
1454                currency_lookups = self._deserialize_currencies(raw_currencies)
1455
1456        return components.CharacterComponent(
1457            activities=activities,
1458            equipment=equipment,
1459            inventory=inventory,
1460            progressions=progressions_,
1461            render_data=render_data,
1462            character=character_,
1463            character_records=character_records,
1464            profile_records=None,
1465            item_components=item_components,
1466            currency_lookups=currency_lookups,
1467            collectibles=collectibles,
1468            nodes=nodes,
1469        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.entity.SearchableEntity]:
1497    def deserialize_inventory_results(
1498        self, payload: typedefs.JSONObject
1499    ) -> iterators.FlatIterator[entity.SearchableEntity]:
1500        suggested_words: list[str] = payload["suggestedWords"]
1501
1502        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1503            return s if not typedefs.is_unknown(s) else undefined.Undefined
1504
1505        return iterators.FlatIterator(
1506            [
1507                entity.SearchableEntity(
1508                    net=self._net,
1509                    hash=data["hash"],
1510                    entity_type=data["entityType"],
1511                    weight=data["weight"],
1512                    suggested_words=suggested_words,
1513                    name=data["displayProperties"]["name"],
1514                    has_icon=data["displayProperties"]["hasIcon"],
1515                    description=_check_unknown(
1516                        data["displayProperties"]["description"]
1517                    ),
1518                    icon=assets.Image(data["displayProperties"]["icon"]),
1519                )
1520                for data in payload["results"]["results"]
1521            ]
1522        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1551    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1552        self, payload: typedefs.JSONObject, /
1553    ) -> entity.InventoryEntity:
1554
1555        props = self._set_entity_attrs(payload)
1556        objects = self._deserialize_inventory_item_objects(payload)
1557
1558        collectible_hash: typing.Optional[int] = None
1559        if raw_collectible_hash := payload.get("collectibleHash"):
1560            collectible_hash = int(raw_collectible_hash)
1561
1562        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1563        if raw_second_icon := payload.get("secondaryIcon"):
1564            secondary_icon = assets.Image(raw_second_icon)
1565
1566        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1567        if raw_second_overlay := payload.get("secondaryOverlay"):
1568            secondary_overlay = assets.Image(raw_second_overlay)
1569
1570        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1571        if raw_second_special := payload.get("secondarySpecial"):
1572            secondary_special = assets.Image(raw_second_special)
1573
1574        screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1575        if raw_screenshot := payload.get("screenshot"):
1576            screenshot = assets.Image(raw_screenshot)
1577
1578        watermark_icon: typing.Optional[assets.Image] = None
1579        if raw_watermark_icon := payload.get("iconWatermark"):
1580            watermark_icon = assets.Image(raw_watermark_icon)
1581
1582        watermark_shelved: typing.Optional[assets.Image] = None
1583        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1584            watermark_shelved = assets.Image(raw_watermark_shelved)
1585
1586        about: undefined.UndefinedOr[str] = undefined.Undefined
1587        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1588            raw_about
1589        ):
1590            about = raw_about
1591
1592        ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined
1593        if (
1594            raw_ui_style := payload.get("uiItemDisplayStyle")
1595        ) and not typedefs.is_unknown(raw_ui_style):
1596            ui_item_style = raw_ui_style
1597
1598        tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined
1599        if (
1600            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1601        ) and not typedefs.is_unknown(raw_tier_and_name):
1602            tier_and_name = raw_tier_and_name
1603
1604        type_name: undefined.UndefinedOr[str] = undefined.Undefined
1605        if (
1606            raw_type_name := payload.get("itemTypeDisplayName")
1607        ) and not typedefs.is_unknown(raw_type_name):
1608            type_name = raw_type_name
1609
1610        display_source: undefined.UndefinedOr[str] = undefined.Undefined
1611        if (
1612            raw_display_source := payload.get("displaySource")
1613        ) and not typedefs.is_unknown(raw_display_source):
1614            display_source = raw_display_source
1615
1616        lorehash: typing.Optional[int] = None
1617        if raw_lore_hash := payload.get("loreHash"):
1618            lorehash = int(raw_lore_hash)
1619
1620        summary_hash: typing.Optional[int] = None
1621        if raw_summary_hash := payload.get("summaryItemHash"):
1622            summary_hash = raw_summary_hash
1623
1624        breaker_type_hash: typing.Optional[int] = None
1625        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1626            breaker_type_hash = int(raw_breaker_type_hash)
1627
1628        damage_types: typing.Optional[collections.Sequence[int]] = None
1629        if raw_damage_types := payload.get("damageTypes"):
1630            damage_types = [int(type_) for type_ in raw_damage_types]
1631
1632        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1633        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1634            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1635
1636        default_damagetype_hash: typing.Optional[int] = None
1637        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1638            default_damagetype_hash = int(raw_defaultdmg_hash)
1639
1640        emblem_objective_hash: typing.Optional[int] = None
1641        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1642            emblem_objective_hash = int(raw_emblem_obj_hash)
1643
1644        tier_type: typing.Optional[enums.TierType] = None
1645        tier: typing.Optional[enums.ItemTier] = None
1646        bucket_hash: typing.Optional[int] = None
1647        recovery_hash: typing.Optional[int] = None
1648        tier_name: undefined.UndefinedOr[str] = undefined.Undefined
1649        isinstance_item: bool = False
1650        expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined
1651        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined
1652        suppress_expiration: bool = False
1653        max_stack_size: typing.Optional[int] = None
1654        stack_label: undefined.UndefinedOr[str] = undefined.Undefined
1655
1656        if inventory := payload.get("inventory"):
1657            tier_type = enums.TierType(int(inventory["tierType"]))
1658            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1659            bucket_hash = int(inventory["bucketTypeHash"])
1660            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1661            tier_name = inventory["tierTypeName"]
1662            isinstance_item = inventory["isInstanceItem"]
1663            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1664            max_stack_size = int(inventory["maxStackSize"])
1665
1666            try:
1667                stack_label = inventory["stackUniqueLabel"]
1668            except KeyError:
1669                pass
1670
1671        return entity.InventoryEntity(
1672            net=self._net,
1673            collectible_hash=collectible_hash,
1674            name=props.name,
1675            about=about,
1676            emblem_objective_hash=emblem_objective_hash,
1677            suppress_expiration=suppress_expiration,
1678            max_stack_size=max_stack_size,
1679            stack_label=stack_label,
1680            tier=tier,
1681            tier_type=tier_type,
1682            tier_name=tier_name,
1683            bucket_hash=bucket_hash,
1684            recovery_bucket_hash=recovery_hash,
1685            isinstance_item=isinstance_item,
1686            expire_in_orbit_message=expire_in_orbit_message,
1687            expiration_tooltip=expire_tool_tip,
1688            lore_hash=lorehash,
1689            type_and_tier_name=tier_and_name,
1690            summary_hash=summary_hash,
1691            ui_display_style=ui_item_style,
1692            type_name=type_name,
1693            breaker_type_hash=breaker_type_hash,
1694            description=props.description,
1695            display_source=display_source,
1696            hash=props.hash,
1697            damage_types=damage_types,
1698            index=props.index,
1699            icon=props.icon,
1700            has_icon=props.has_icon,
1701            screenshot=screenshot,
1702            watermark_icon=watermark_icon,
1703            watermark_shelved=watermark_shelved,
1704            secondary_icon=secondary_icon,
1705            secondary_overlay=secondary_overlay,
1706            secondary_special=secondary_special,
1707            type=enums.ItemType(int(payload["itemType"])),
1708            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1709            trait_ids=[trait for trait in payload.get("traitIds", [])],
1710            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1711            item_class=enums.Class(int(payload["classType"])),
1712            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1713            breaker_type=int(payload["breakerType"]),
1714            default_damagetype=int(payload["defaultDamageType"]),
1715            default_damagetype_hash=default_damagetype_hash,
1716            damagetype_hashes=damagetype_hashes,
1717            tooltip_notifications=payload["tooltipNotifications"],
1718            not_transferable=payload["nonTransferrable"],
1719            allow_actions=payload["allowActions"],
1720            is_equippable=payload["equippable"],
1721            objects=objects,
1722            background_colors=payload.get("backgroundColor", {}),
1723            season_hash=payload.get("seasonHash"),
1724            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1725        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1727    def deserialize_objective_entity(
1728        self, payload: typedefs.JSONObject, /
1729    ) -> entity.ObjectiveEntity:
1730        props = self._set_entity_attrs(payload)
1731        return entity.ObjectiveEntity(
1732            net=self._net,
1733            hash=props.hash,
1734            index=props.index,
1735            description=props.description,
1736            name=props.name,
1737            has_icon=props.has_icon,
1738            icon=props.icon,
1739            unlock_value_hash=payload["unlockValueHash"],
1740            completion_value=payload["completionValue"],
1741            scope=entity.GatingScope(int(payload["scope"])),
1742            location_hash=payload["locationHash"],
1743            allowed_negative_value=payload["allowNegativeValue"],
1744            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1745            counting_downward=payload["isCountingDownward"],
1746            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1747            progress_description=payload["progressDescription"],
1748            perks=payload["perks"],
1749            stats=payload["stats"],
1750            minimum_visibility=payload["minimumVisibilityThreshold"],
1751            allow_over_completion=payload["allowOvercompletion"],
1752            show_value_style=payload["showValueOnComplete"],
1753            display_only_objective=payload["isDisplayOnlyObjective"],
1754            complete_value_style=entity.ValueUIStyle(
1755                int(payload["completedValueStyle"])
1756            ),
1757            progress_value_style=entity.ValueUIStyle(
1758                int(payload["inProgressValueStyle"])
1759            ),
1760            ui_label=payload["uiLabel"],
1761            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1762        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1790    def deserialize_activity(
1791        self,
1792        payload: typedefs.JSONObject,
1793        /,
1794    ) -> activity.Activity:
1795        period = time.clean_date(payload["period"])
1796        details = payload["activityDetails"]
1797        ref_id = int(details["referenceId"])
1798        instance_id = int(details["instanceId"])
1799        mode = enums.GameMode(details["mode"])
1800        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1801        is_private = details["isPrivate"]
1802        membership_type = enums.MembershipType(int(details["membershipType"]))
1803
1804        # Since we're using the same fields for post activity method
1805        # this check is required since post activity doesn't values values
1806        values = self._deserialize_activity_values(payload["values"])
1807
1808        return activity.Activity(
1809            net=self._net,
1810            hash=ref_id,
1811            instance_id=instance_id,
1812            mode=mode,
1813            modes=modes,
1814            is_private=is_private,
1815            membership_type=membership_type,
1816            occurred_at=period,
1817            values=values,
1818        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.activity.Activity]:
1820    def deserialize_activities(
1821        self, payload: typedefs.JSONObject
1822    ) -> iterators.FlatIterator[activity.Activity]:
1823        return iterators.FlatIterator(
1824            [
1825                self.deserialize_activity(activity_)
1826                for activity_ in payload["activities"]
1827            ]
1828        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
  • aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
def deserialize_extended_weapon_values( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1830    def deserialize_extended_weapon_values(
1831        self, payload: typedefs.JSONObject
1832    ) -> activity.ExtendedWeaponValues:
1833
1834        assists: typing.Optional[int] = None
1835        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1836            assists = raw_assists["basic"]["value"]
1837        assists_damage: typing.Optional[int] = None
1838
1839        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1840            assists_damage = raw_assists_damage["basic"]["value"]
1841
1842        return activity.ExtendedWeaponValues(
1843            reference_id=int(payload["referenceId"]),
1844            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1845            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1846                "value"
1847            ],
1848            assists=assists,
1849            assists_damage=assists_damage,
1850            precision_kills_percentage=(
1851                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1852                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1853                    "displayValue"
1854                ],
1855            ),
1856        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1879    def deserialize_post_activity_player(
1880        self, payload: typedefs.JSONObject, /
1881    ) -> activity.PostActivityPlayer:
1882        player = payload["player"]
1883
1884        class_hash: typedefs.NoneOr[int] = None
1885        if (class_hash := player.get("classHash")) is not None:
1886            class_hash = class_hash
1887
1888        race_hash: typedefs.NoneOr[int] = None
1889        if (race_hash := player.get("raceHash")) is not None:
1890            race_hash = race_hash
1891
1892        gender_hash: typedefs.NoneOr[int] = None
1893        if (gender_hash := player.get("genderHash")) is not None:
1894            gender_hash = gender_hash
1895
1896        character_class: undefined.UndefinedOr[str] = undefined.Undefined
1897        if (
1898            character_class := player.get("characterClass")
1899        ) and not typedefs.is_unknown(character_class):
1900            character_class = character_class
1901
1902        character_level: typedefs.NoneOr[int] = None
1903        if (character_level := player.get("characterLevel")) is not None:
1904            character_level = character_level
1905
1906        return activity.PostActivityPlayer(
1907            standing=int(payload["standing"]),
1908            score=int(payload["score"]["basic"]["value"]),
1909            character_id=payload["characterId"],
1910            destiny_user=self.deserialize_destiny_membership(
1911                payload["player"]["destinyUserInfo"]
1912            ),
1913            character_class=character_class,
1914            character_level=character_level,
1915            race_hash=race_hash,
1916            gender_hash=gender_hash,
1917            class_hash=class_hash,
1918            light_level=int(payload["player"]["lightLevel"]),
1919            emblem_hash=int(payload["player"]["emblemHash"]),
1920            values=self._deserialize_activity_values(payload["values"]),
1921            extended_values=self._deserialize_extended_values(payload["extended"]),
1922        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1934    def deserialize_post_activity(
1935        self, payload: typedefs.JSONObject
1936    ) -> activity.PostActivity:
1937        period = time.clean_date(payload["period"])
1938        details = payload["activityDetails"]
1939        ref_id = int(details["referenceId"])
1940        instance_id = int(details["instanceId"])
1941        mode = enums.GameMode(details["mode"])
1942        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1943        is_private = details["isPrivate"]
1944        membership_type = enums.MembershipType(int(details["membershipType"]))
1945        return activity.PostActivity(
1946            net=self._net,
1947            hash=ref_id,
1948            membership_type=membership_type,
1949            instance_id=instance_id,
1950            mode=mode,
1951            modes=modes,
1952            is_private=is_private,
1953            occurred_at=period,
1954            starting_phase=int(payload["startingPhaseIndex"]),
1955            players=[
1956                self.deserialize_post_activity_player(player)
1957                for player in payload["entries"]
1958            ],
1959            teams=[
1960                self._deserialize_post_activity_team(team) for team in payload["teams"]
1961            ],
1962        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
2000    def deserialize_aggregated_activity(
2001        self, payload: typedefs.JSONObject
2002    ) -> activity.AggregatedActivity:
2003        return activity.AggregatedActivity(
2004            hash=int(payload["activityHash"]),
2005            values=self._deserialize_aggregated_activity_values(payload["values"]),
2006        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.activity.AggregatedActivity]:
2008    def deserialize_aggregated_activities(
2009        self, payload: typedefs.JSONObject
2010    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
2011        return iterators.FlatIterator(
2012            [
2013                self.deserialize_aggregated_activity(activity)
2014                for activity in payload["activities"]
2015            ]
2016        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
2018    def deserialize_linked_profiles(
2019        self, payload: typedefs.JSONObject
2020    ) -> profile.LinkedProfile:
2021        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2022        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2023        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2024
2025        if raw_profile := payload.get("profiles"):
2026            for pfile in raw_profile:
2027                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2028
2029        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2030            for raw_error_pfile in raw_profiles_with_errors:
2031                if error_pfile := raw_error_pfile.get("infoCard"):
2032                    error_profiles_vec.append(
2033                        self.deserialize_destiny_membership(error_pfile)
2034                    )
2035
2036        return profile.LinkedProfile(
2037            net=self._net,
2038            bungie=bungie_user,
2039            profiles=profiles_vec,
2040            profiles_with_errors=error_profiles_vec,
2041        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
2043    def deserialize_clan_banners(
2044        self, payload: typedefs.JSONObject
2045    ) -> collections.Sequence[clans.ClanBanner]:
2046        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2047        if banners := payload.get("clanBannerDecals"):
2048            for k, v in banners.items():
2049                banner_obj = clans.ClanBanner(
2050                    id=int(k),
2051                    foreground=assets.Image(v["foregroundPath"]),
2052                    background=assets.Image(v["backgroundPath"]),
2053                )
2054                banners_seq.append(banner_obj)
2055        return banners_seq

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
2057    def deserialize_public_milestone_content(
2058        self, payload: typedefs.JSONObject
2059    ) -> milestones.MilestoneContent:
2060        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2061        if raw_categories := payload.get("itemCategories"):
2062            for item in raw_categories:
2063                title = undefined.Undefined
2064                if raw_title := item.get("title"):
2065                    if raw_title != typedefs.Unknown:
2066                        title = raw_title
2067                if raw_hashes := item.get("itemHashes"):
2068                    hashes: collections.Sequence[int] = raw_hashes
2069
2070                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2071
2072        about = undefined.Undefined
2073        if (raw_about := payload["about"]) != typedefs.Unknown:
2074            about = raw_about
2075
2076        status = undefined.Undefined
2077        if (raw_status := payload["status"]) != typedefs.Unknown:
2078            status = raw_status
2079
2080        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2081        if raw_tips := payload.get("tips"):
2082            for raw_tip in raw_tips:
2083                if raw_tip == typedefs.Unknown:
2084                    raw_tip = undefined.Undefined
2085                tips.append(raw_tip)
2086
2087        return milestones.MilestoneContent(
2088            about=about, status=status, tips=tips, items=items_categoris
2089        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2091    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2092        name = undefined.Undefined
2093        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2094            name = raw_name
2095
2096        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2097
2098        if raw_bungie_user := payload.get("bungieNetUser"):
2099            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2100
2101        return friends.Friend(
2102            net=self._net,
2103            id=int(payload["lastSeenAsMembershipId"]),
2104            name=name,
2105            code=payload.get("bungieGlobalDisplayNameCode"),
2106            relationship=enums.Relationship(payload["relationship"]),
2107            user=bungie_user,
2108            online_status=enums.Presence(payload["onlineStatus"]),
2109            online_title=payload["onlineTitle"],
2110            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2111        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2113    def deserialize_friends(
2114        self, payload: typedefs.JSONObject
2115    ) -> collections.Sequence[friends.Friend]:
2116        mut_seq: typing.MutableSequence[friends.Friend] = []
2117        if raw_friends := payload.get("friends"):
2118            for friend in raw_friends:
2119                mut_seq.append(self.deserialize_friend(friend))
2120        return mut_seq

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: dict[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2122    def deserialize_friend_requests(
2123        self, payload: typedefs.JSONObject
2124    ) -> friends.FriendRequestView:
2125        incoming: typing.MutableSequence[friends.Friend] = []
2126        outgoing: typing.MutableSequence[friends.Friend] = []
2127
2128        if raw_incoming_requests := payload.get("incomingRequests"):
2129            for incoming_request in raw_incoming_requests:
2130                incoming.append(self.deserialize_friend(incoming_request))
2131
2132        if raw_outgoing_requests := payload.get("outgoingRequests"):
2133            for outgoing_request in raw_outgoing_requests:
2134                outgoing.append(self.deserialize_friend(outgoing_request))
2135
2136        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: dict[str, typing.Any]) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
2161    def deserialize_fireteams(
2162        self, payload: typedefs.JSONObject
2163    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2164        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2165
2166        result: list[typedefs.JSONObject]
2167        if not (result := payload["results"]):
2168            return None
2169        for elem in result:
2170            fireteams_.append(
2171                self._set_fireteam_fields(
2172                    elem, total_results=int(payload["totalResults"])
2173                )
2174            )
2175        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2177    def deserialize_fireteam_destiny_users(
2178        self, payload: typedefs.JSONObject
2179    ) -> fireteams.FireteamUser:
2180        destiny_obj = self.deserialize_destiny_membership(payload)
2181        # We could helpers.just return a DestinyMembership object but this is
2182        # missing the fireteam display name and id fields.
2183        return fireteams.FireteamUser(
2184            net=self._net,
2185            id=destiny_obj.id,
2186            code=destiny_obj.code,
2187            icon=destiny_obj.icon,
2188            types=destiny_obj.types,
2189            type=destiny_obj.type,
2190            is_public=destiny_obj.is_public,
2191            crossave_override=destiny_obj.crossave_override,
2192            name=destiny_obj.name,
2193            last_seen_name=destiny_obj.last_seen_name,
2194            fireteam_display_name=payload["FireteamDisplayName"],
2195            fireteam_membership_id=enums.MembershipType(
2196                payload["FireteamMembershipType"]
2197            ),
2198        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: dict[str, typing.Any], *, alternatives: bool = False) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]]:
2200    def deserialize_fireteam_members(
2201        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2202    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2203        members_: list[fireteams.FireteamMember] = []
2204        if members := payload.get("Members" if not alternatives else "Alternates"):
2205            for member in members:
2206                bungie_fields = self.deserialize_partial_bungie_user(member)
2207                members_fields = fireteams.FireteamMember(
2208                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2209                    has_microphone=member["hasMicrophone"],
2210                    character_id=int(member["characterId"]),
2211                    date_joined=time.clean_date(member["dateJoined"]),
2212                    last_platform_invite_date=time.clean_date(
2213                        member["lastPlatformInviteAttemptDate"]
2214                    ),
2215                    last_platform_invite_result=int(
2216                        member["lastPlatformInviteAttemptResult"]
2217                    ),
2218                    net=self._net,
2219                    name=bungie_fields.name,
2220                    id=bungie_fields.id,
2221                    icon=bungie_fields.icon,
2222                    is_public=bungie_fields.is_public,
2223                    crossave_override=bungie_fields.crossave_override,
2224                    types=bungie_fields.types,
2225                    type=bungie_fields.type,
2226                )
2227                members_.append(members_fields)
2228        else:
2229            return None
2230        return members_

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteams( self, data: dict[str, typing.Any], *, no_results: bool = False) -> Union[aiobungie.crates.fireteams.AvailableFireteam, collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]:
2232    def deserialize_available_fireteams(
2233        self,
2234        data: typedefs.JSONObject,
2235        *,
2236        no_results: bool = False,
2237    ) -> typing.Union[
2238        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2239    ]:
2240        fireteams_: list[fireteams.AvailableFireteam] = []
2241
2242        # This needs to be used outside the results
2243        # JSON key.
2244        if no_results is True:
2245            payload = data
2246
2247        if result := payload.get("results"):
2248
2249            for fireteam in result:
2250                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2251                fireteams_fields = fireteams.AvailableFireteam(
2252                    id=found_fireteams.id,
2253                    group_id=found_fireteams.group_id,
2254                    platform=found_fireteams.platform,
2255                    activity_type=found_fireteams.activity_type,
2256                    is_immediate=found_fireteams.is_immediate,
2257                    is_public=found_fireteams.is_public,
2258                    is_valid=found_fireteams.is_valid,
2259                    owner_id=found_fireteams.owner_id,
2260                    player_slot_count=found_fireteams.player_slot_count,
2261                    available_player_slots=found_fireteams.available_player_slots,
2262                    available_alternate_slots=found_fireteams.available_alternate_slots,
2263                    title=found_fireteams.title,
2264                    date_created=found_fireteams.date_created,
2265                    locale=found_fireteams.locale,
2266                    last_modified=found_fireteams.last_modified,
2267                    total_results=found_fireteams.total_results,
2268                    members=self.deserialize_fireteam_members(payload),
2269                    alternatives=self.deserialize_fireteam_members(
2270                        payload, alternatives=True
2271                    ),
2272                )
2273            fireteams_.append(fireteams_fields)
2274            if no_results:
2275                return fireteams_fields
2276        return fireteams_

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • no_results (bool): Whether to deserialize the data from results in the payload or not.
Returns
  • typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]] # noqa (E501): An available fireteam or a sequence of available fireteam.
def deserialize_fireteam_party( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2278    def deserialize_fireteam_party(
2279        self, payload: typedefs.JSONObject
2280    ) -> fireteams.FireteamParty:
2281        last_destination_hash: typing.Optional[int] = None
2282        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2283            last_destination_hash = int(raw_dest_hash)
2284
2285        return fireteams.FireteamParty(
2286            members=[
2287                self._deserialize_fireteam_party_member(member)
2288                for member in payload["partyMembers"]
2289            ],
2290            activity=self._deserialize_fireteam_party_current_activity(
2291                payload["currentActivity"]
2292            ),
2293            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2294            last_destination_hash=last_destination_hash,
2295            tracking=payload["tracking"],
2296        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact(self, payload: dict[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2343    def deserialize_seasonal_artifact(
2344        self, payload: typedefs.JSONObject
2345    ) -> season.Artifact:
2346        if raw_artifact := payload.get("seasonalArtifact"):
2347            if points := raw_artifact.get("pointProgression"):
2348                points_prog = progressions.Progression(
2349                    hash=points["progressionHash"],
2350                    level=points["level"],
2351                    cap=points["levelCap"],
2352                    daily_limit=points["dailyLimit"],
2353                    weekly_limit=points["weeklyLimit"],
2354                    current_progress=points["currentProgress"],
2355                    daily_progress=points["dailyProgress"],
2356                    needed=points["progressToNextLevel"],
2357                    next_level=points["nextLevelAt"],
2358                )
2359
2360            if bonus := raw_artifact.get("powerBonusProgression"):
2361                power_bonus_prog = progressions.Progression(
2362                    hash=bonus["progressionHash"],
2363                    level=bonus["level"],
2364                    cap=bonus["levelCap"],
2365                    daily_limit=bonus["dailyLimit"],
2366                    weekly_limit=bonus["weeklyLimit"],
2367                    current_progress=bonus["currentProgress"],
2368                    daily_progress=bonus["dailyProgress"],
2369                    needed=bonus["progressToNextLevel"],
2370                    next_level=bonus["nextLevelAt"],
2371                )
2372            artifact = season.Artifact(
2373                net=self._net,
2374                hash=raw_artifact["artifactHash"],
2375                power_bonus=raw_artifact["powerBonus"],
2376                acquired_points=raw_artifact["pointsAcquired"],
2377                bonus=power_bonus_prog,
2378                points=points_prog,
2379            )
2380        return artifact

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2382    def deserialize_profile_progression(
2383        self, payload: typedefs.JSONObject
2384    ) -> profile.ProfileProgression:
2385        return profile.ProfileProgression(
2386            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2387            checklist={
2388                int(check_id): checklists
2389                for check_id, checklists in payload["data"]["checklists"].items()
2390            },
2391        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2393    def deserialize_instanced_item(
2394        self, payload: typedefs.JSONObject
2395    ) -> items.ItemInstance:
2396        damage_type_hash: typing.Optional[int] = None
2397        if raw_damagetype_hash := payload.get("damageTypeHash"):
2398            damage_type_hash = int(raw_damagetype_hash)
2399
2400        required_hashes: typing.Optional[collections.Collection[int]] = None
2401        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2402            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2403
2404        breaker_type: typing.Optional[items.ItemBreakerType] = None
2405        if raw_break_type := payload.get("breakerType"):
2406            breaker_type = items.ItemBreakerType(int(raw_break_type))
2407
2408        breaker_type_hash: typing.Optional[int] = None
2409        if raw_break_type_hash := payload.get("breakerTypeHash"):
2410            breaker_type_hash = int(raw_break_type_hash)
2411
2412        energy: typing.Optional[items.ItemEnergy] = None
2413        if raw_energy := payload.get("energy"):
2414            energy = self.deserialize_item_energy(raw_energy)
2415
2416        primary_stats = None
2417        if raw_primary_stats := payload.get("primaryStat"):
2418            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2419
2420        return items.ItemInstance(
2421            damage_type=enums.DamageType(int(payload["damageType"])),
2422            damage_type_hash=damage_type_hash,
2423            primary_stat=primary_stats,
2424            item_level=int(payload["itemLevel"]),
2425            quality=int(payload["quality"]),
2426            is_equipped=payload["isEquipped"],
2427            can_equip=payload["canEquip"],
2428            equip_required_level=int(payload["equipRequiredLevel"]),
2429            required_equip_unlock_hashes=required_hashes,
2430            cant_equip_reason=int(payload["cannotEquipReason"]),
2431            breaker_type=breaker_type,
2432            breaker_type_hash=breaker_type_hash,
2433            energy=energy,
2434        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2436    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2437        energy_hash: typing.Optional[int] = None
2438        if raw_energy_hash := payload.get("energyTypeHash"):
2439            energy_hash = int(raw_energy_hash)
2440
2441        return items.ItemEnergy(
2442            hash=energy_hash,
2443            type=items.ItemEnergyType(int(payload["energyType"])),
2444            capacity=int(payload["energyCapacity"]),
2445            used_energy=int(payload["energyUsed"]),
2446            unused_energy=int(payload["energyUnused"]),
2447        )
def deserialize_item_perk(self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2449    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2450        perk_hash: typing.Optional[int] = None
2451        if raw_perk_hash := payload.get("perkHash"):
2452            perk_hash = int(raw_perk_hash)
2453
2454        return items.ItemPerk(
2455            hash=perk_hash,
2456            icon=assets.Image(payload["iconPath"]),
2457            is_active=payload["isActive"],
2458            is_visible=payload["visible"],
2459        )
def deserialize_item_socket( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2461    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2462        plug_hash: typing.Optional[int] = None
2463        if raw_plug_hash := payload.get("plugHash"):
2464            plug_hash = int(raw_plug_hash)
2465
2466        enable_fail_indexes: typing.Optional[list[int]] = None
2467        if raw_indexes := payload.get("enableFailIndexes"):
2468            enable_fail_indexes = [int(index) for index in raw_indexes]
2469
2470        return items.ItemSocket(
2471            plug_hash=plug_hash,
2472            is_enabled=payload["isEnabled"],
2473            enable_fail_indexes=enable_fail_indexes,
2474            is_visible=payload.get("visible"),
2475        )
def deserialize_item_stats_view( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2477    def deserialize_item_stats_view(
2478        self, payload: typedefs.JSONObject
2479    ) -> items.ItemStatsView:
2480        return items.ItemStatsView(
2481            stat_hash=payload.get("statHash"), value=payload.get("value")
2482        )
def deserialize_plug_item_state( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2484    def deserialize_plug_item_state(
2485        self, payload: typedefs.JSONObject
2486    ) -> items.PlugItemState:
2487        item_hash: typing.Optional[int] = None
2488        if raw_item_hash := payload.get("plugItemHash"):
2489            item_hash = int(raw_item_hash)
2490
2491        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2492        if raw_fail_indexes := payload.get("insertFailIndexes"):
2493            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2494
2495        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2496        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2497            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2498
2499        return items.PlugItemState(
2500            item_hash=item_hash,
2501            insert_fail_indexes=insert_fail_indexes,
2502            enable_fail_indexes=enable_fail_indexes,
2503            is_enabled=payload["enabled"],
2504            can_insert=payload["canInsert"],
2505        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 68@typing.final
 69class FireteamActivity(int, enums.Enum):
 70    """An enum for the fireteam activities."""
 71
 72    ALL = 0
 73    CRUCIBLE = 2
 74    TRIALS_OF_OSIRIS = 3
 75    NIGHTFALL = 4
 76    ANY = 5
 77    GAMBIT = 6
 78    BLIND_WELL = 7
 79    NIGHTMARE_HUNTS = 12
 80    ALTARS_OF_SORROWS = 14
 81    DUNGEON = 15
 82    RAID_LW = 20
 83    RAID_GOS = 21
 84    RAID_DSC = 22
 85    EXO_CHALLENGE = 23
 86    S12_WRATHBORN = 24
 87    EMPIRE_HUNTS = 25
 88    S13_BATTLEGROUNDS = 26
 89    EXOTIC_QUEST = 27
 90    RAID_VOG = 28
 91    S14_EXPUNGE = 30
 92    S15_ASTRAL_ALIGNMENT = 31
 93    S15_SHATTERED_RELAM = 32
 94    SHATTERED_THRONE = 33
 95    PROPHECY = 34
 96    PIT_OF_HERESY = 35
 97    DOE = 36
 98    """Dares of Eternity."""
 99    DUNGEON_GOA = 37
100    """Grasp of Avarice."""
101    VOW_OF_THE_DISCPILE = 38
102    CAMPAIGN = 39
103    WELLSPRING = 40
104    S16_BATTLEGROUNDS = 41
105    S17_NIGHTMARE_CONTAINMENT = 44
106    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
132@typing.final
133class FireteamDate(int, enums.Enum):
134    """An enum for fireteam date ranges."""
135
136    ALL = 0
137    NOW = 1
138    TODAY = 2
139    TWO_DAYS = 3
140    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
109@typing.final
110class FireteamLanguage(str, enums.Enum):
111    """An enum for fireteams languages filters."""
112
113    ALL = ""
114    ENGLISH = "en"
115    FRENCH = "fr"
116    ESPANOL = "es"
117    DEUTSCH = "de"
118    ITALIAN = "it"
119    JAPANESE = "ja"
120    PORTUGUESE = "pt-br"
121    RUSSIAN = "ru"
122    POLISH = "pl"
123    KOREAN = "ko"
124    # ? China
125    ZH_CHT = "zh-cht"
126    ZH_CHS = "zh-chs"
127
128    def __str__(self) -> str:
129        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
55@typing.final
56class FireteamPlatform(int, enums.Enum):
57    """An enum for fireteam related to bungie fireteams.
58    This is different from the normal `aiobungie.MembershipType`.
59    """
60
61    ANY = 0
62    PSN_NETWORK = 1
63    XBOX_LIVE = 2
64    STEAM = 4
65    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Flag(enum.Flag):
102class Flag(__enum.Flag):
103    """Builtin Python enum flag with extra handlings."""
104
105    # Needs to type this here for mypy
106    _value_: int
107
108    @property
109    def name(self) -> str:  # type: ignore[override]
110        if self._name_ is None:
111            self._name_ = f"UNKNOWN {self._value_}"
112
113        return self._name_
114
115    @property
116    def value(self) -> int:  # type: ignore[override]
117        return self._value_
118
119    def __str__(self) -> str:
120        return self.name
121
122    def __repr__(self) -> str:
123        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
124
125    def __int__(self) -> int:
126        if isinstance(self.value, _ITERABLE):
127            raise TypeError(
128                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
129            )
130        return int(self.value)
131
132    def __or__(self, other: typing.Union[Flag, int]) -> Flag:
133        return self.__class__(self._value_ | int(other))
134
135    def __xor__(self, other: typing.Union[Flag, int]) -> Flag:
136        return self.__class__(self._value_ ^ int(other))
137
138    def __and__(self, other: typing.Union[Flag, int]) -> Flag:
139        return self.__class__(other & int(other))
140
141    def __invert__(self) -> Flag:
142        return self.__class__(~self._value_)
143
144    def __contains__(self, other: typing.Union[Flag, int]) -> bool:
145        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str
value: int
class FlatIterator(typing.Generic[~Item]):
 43class FlatIterator(typing.Generic[Item]):
 44    """A Flat, In-Memory iterator for sequenced based data.
 45
 46    This can either be used sync or asynchronously.
 47
 48    Example
 49    -------
 50    ```py
 51    iterator = FlatIterator([1, 2, 3])
 52
 53    # Limit the results to 2.
 54    async for item in iterator.take(2):
 55        print(item)
 56    # 1
 57    # 2
 58
 59    # Filter the results.
 60    async for item in iterator.filter(lambda item: item > 1):
 61        print(item)
 62        print(iterator.count())
 63    # 2
 64    # 3
 65    # 3
 66
 67    # Map the results.
 68    async for item in iterator.map(lambda item: item * 2):
 69        print(item)
 70    # 2
 71    # 4
 72
 73    # This also works synchronously.
 74    iterator = FlatIterator(["Hello", "World", "!"])
 75    for item in iterator.discard(lambda item: "!" in item):
 76        print(item)
 77    # Hello
 78    # World
 79
 80    # Indexing is also supported.
 81
 82    print(iterator[0])
 83    # Hello
 84    ```
 85
 86    Parameters
 87    ----------
 88    items: `collections.Iterable[Item]`
 89        The items to iterate over.
 90    """
 91
 92    __slots__ = ("_items",)
 93
 94    def __init__(self, items: collections.Iterable[Item]) -> None:
 95        self._items = iter(items)
 96
 97    @typing.overload
 98    def collect(self) -> list[Item]:
 99        ...
100
101    @typing.overload
102    def collect(self, casting: _B) -> list[_B]:
103        """Collects all items in the iterator into a list and cast them into an object if provided.
104
105        Example
106        -------
107        >>> iterator = FlatIterator([1, 2, 3])
108        >>> iterator.collect(casting=str)
109        ["1", "2", "3"]
110
111        Parameters
112        ----------
113        casting: `T | None`
114            The type to cast the items to. If `None` is provided, the items will be returned as is.
115
116        Raises
117        ------
118        `StopIteration`
119            If no elements are left in the iterator.
120        """
121        ...
122
123    def collect(
124        self, casting: typing.Optional[_B] = None
125    ) -> typing.Union[list[Item], list[_B]]:
126        """Collects all items in the iterator into a list.
127
128        Example
129        -------
130        >>> iterator = FlatIterator([1, 2, 3])
131        >>> iterator.collect()
132        [1, 2, 3]
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        if casting is not None:
140            return typing.cast(list[_B], list(map(casting, self._items)))
141
142        return list(self._items)
143
144    def next(self) -> Item:
145        """Returns the next item in the iterator.
146
147        Example
148        -------
149        >>> iterator = FlatIterator[str](["1", "2", "3"])
150        item = iterator.next()
151        assert item == "1"
152        item = iterator.next()
153        assert item == "2"
154
155        Raises
156        ------
157        `StopIteration`
158            If no elements are left in the iterator.
159        """
160        try:
161            return self.__next__()
162        except StopIteration:
163            self._ok()
164
165    def map(
166        self, predicate: collections.Callable[[Item], OtherItem]
167    ) -> FlatIterator[OtherItem]:
168        """Maps each item in the iterator to its predicated value.
169
170        Example
171        -------
172        >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
173        <FlatIterator([1, 2, 3])>
174        >>> async for item in iterator:
175                assert isinstance(item, int)
176
177        Parameters
178        ----------
179        predicate: `collections.Callable[[Item], Item]`
180            The function to map each item in the iterator to its predicated value.
181
182        Raises
183        ------
184        `StopIteration`
185            If no elements are left in the iterator.
186        """
187        return FlatIterator(map(predicate, self._items))
188
189    def take(self, n: int) -> FlatIterator[Item]:
190        """Take the first number of items until the number of items are yielded or
191        the end of the iterator is reached.
192
193        Example
194        -------
195        >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
196        >>> async for mode in iterator.take(2):
197                assert mode in [GameMode.RAID, GameMode.STRIKE]
198        <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
199
200        Parameters
201        ----------
202        n: `int`
203            The number of items to take.
204
205        Raises
206        ------
207        `StopIteration`
208            If no elements are left in the iterator.
209        """
210        return FlatIterator(itertools.islice(self._items, n))
211
212    def take_while(
213        self, predicate: collections.Callable[[Item], bool]
214    ) -> FlatIterator[Item]:
215        """Yields items from the iterator while predicate returns `True`.
216
217        Example
218        -------
219        ```py
220        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
221
222        async for platform in (
223            iterator
224            .take_while(lambda platform: platform is not MembershipType.XBOX)
225        ):
226                print(platform)
227        # <FlatIterator([MembershipType.STEAM])>
228        ```
229
230        Parameters
231        ----------
232        predicate: `collections.Callable[[Item], bool]`
233            The function to predicate each item in the iterator.
234
235        Raises
236        ------
237        `StopIteration`
238            If no elements are left in the iterator.
239        """
240        return FlatIterator(itertools.takewhile(predicate, self._items))
241
242    def drop_while(
243        self, predicate: collections.Callable[[Item], bool]
244    ) -> FlatIterator[Item]:
245        """Yields items from the iterator while predicate returns `False`.
246
247        Example
248        -------
249        ```py
250        iterator = FlatIterator(
251            [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
252        )
253
254        async for membership in (
255            iterator
256            .drop_while(lambda membership: membership.name is not "Jim")
257        ):
258                print(membership)
259        # <FlatIterator([DestinyMembership(name="Bob")])>
260        ```
261
262        Parameters
263        ----------
264        predicate: `collections.Callable[[Item], bool]`
265            The function to predicate each item in the iterator.
266
267        Raises
268        ------
269        `StopIteration`
270            If no elements are left in the iterator.
271        """
272        return FlatIterator(itertools.dropwhile(predicate, self._items))
273
274    def filter(
275        self, predicate: collections.Callable[[Item], bool]
276    ) -> FlatIterator[Item]:
277        """Filters the iterator to only yield items that match the predicate.
278
279        Example
280        -------
281        ```py
282        activities = FlatIterator(
283            [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
284            # Assuming Raid is solo, Strike is flawless.
285        )
286
287        async for activity in (
288            activities
289            .filter(lambda activity: activity.is_solo or activity.is_flawless)
290        ):
291                print(member)
292        # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
293        ```
294        """
295        return FlatIterator(filter(predicate, self._items))
296
297    def skip(self, n: int) -> FlatIterator[Item]:
298        """Skips the first number of items in the iterator.
299
300        Example
301        -------
302        ```py
303        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
304
305        async for platform in iterator.skip(1):
306                print(platform)
307        # Skip the first item in the iterator.
308        # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
309        """
310        return FlatIterator(itertools.islice(self._items, n, None))
311
312    def discard(
313        self, predicate: collections.Callable[[Item], bool]
314    ) -> FlatIterator[Item]:
315        """Discards all elements in the iterator for which the predicate function returns true.
316
317        Example
318        -------
319        >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
320        >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
321                # Drops all memberships that are not steam.
322                print(iterator)
323        <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
324
325        Parameters
326        ----------
327        predicate: `collections.Callable[[Item], bool]`
328            The function to test each item in the iterator.
329
330        Raises
331        ------
332        `StopIteration`
333            If no elements are left in the iterator.
334        """
335        return FlatIterator(filter(lambda x: not predicate(x), self._items))
336
337    def zip(
338        self, other: FlatIterator[OtherItem]
339    ) -> FlatIterator[tuple[Item, OtherItem]]:
340        """Zips the iterator with another iterable.
341
342        Example
343        -------
344        >>> iterator = FlatIterator([1, 2, 3])
345        >>> other = FlatIterator([4, 5, 6])
346        >>> async for item, other_item in iterator.zip(other):
347                assert item == other_item
348        <FlatIterator([(1, 4), (2, 5), (3, 6)])>
349
350        Parameters
351        ----------
352        other: `FlatIterator[OtherItem]`
353            The iterable to zip with.
354
355        Raises
356        ------
357        `StopIteration`
358            If no elements are left in the iterator.
359        """
360        return FlatIterator(zip(self._items, other))
361
362    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
363        """`True` if all items in the iterator match the predicate.
364
365        Example
366        -------
367        >>> iterator = FlatIterator([1, 2, 3])
368        >>> while iterator.all(lambda item: isinstance(item, int)):
369                print("Still all integers")
370                continue
371            # Still all integers
372
373        Parameters
374        ----------
375        predicate: `collections.Callable[[Item], bool]`
376            The function to test each item in the iterator.
377
378        Raises
379        ------
380        `StopIteration`
381            If no elements are left in the iterator.
382        """
383        return all(predicate(item) for item in self)
384
385    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
386        """`True` if any items in the iterator match the predicate.
387
388        Example
389        -------
390        >>> iterator = FlatIterator([1, 2, 3])
391        >>> if iterator.any(lambda item: isinstance(item, int)):
392                print("At least one item is an int.")
393        # At least one item is an int.
394
395        Parameters
396        ----------
397        predicate: `collections.Callable[[Item], bool]`
398            The function to test each item in the iterator.
399
400        Raises
401        ------
402        `StopIteration`
403            If no elements are left in the iterator.
404        """
405        return any(predicate(item) for item in self)
406
407    def sort(
408        self,
409        *,
410        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
411        reverse: bool = False,
412    ) -> FlatIterator[Item]:
413        """Sorts the iterator.
414
415        Example
416        -------
417        >>> iterator = FlatIterator([3, 1, 6, 7])
418        >>> async for item in iterator.sort(key=lambda item: item < 3):
419                print(item)
420        # 1
421        # 3
422        # 6
423        # 7
424
425        Parameters
426        ----------
427        key: `collections.Callable[[Item], Any]`
428            The function to sort by.
429        reverse: `bool`
430            Whether to reverse the sort.
431
432        Raises
433        ------
434        `StopIteration`
435            If no elements are left in the iterator.
436        """
437        return FlatIterator(sorted(self._items, key=key, reverse=reverse))
438
439    def first(self) -> Item:
440        """Returns the first item in the iterator.
441
442        Example
443        -------
444        >>> iterator = FlatIterator([3, 1, 6, 7])
445        >>> iterator.first()
446        3
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return self.take(1).next()
454
455    def reversed(self) -> FlatIterator[Item]:
456        """Returns a new iterator that yields the items in the iterator in reverse order.
457
458        Example
459        -------
460        >>> iterator = FlatIterator([3, 1, 6, 7])
461        >>> async for item in iterator.reversed():
462                print(item)
463        # 7
464        # 6
465        # 1
466        # 3
467
468        Raises
469        ------
470        `StopIteration`
471            If no elements are left in the iterator.
472        """
473        return FlatIterator(reversed(self.collect()))
474
475    def count(self) -> int:
476        count = 0
477        for _ in self:
478            count += 1
479
480        return count
481
482    def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
483        """Returns a new iterator that yields all items from both iterators.
484
485        Example
486        -------
487        >>> iterator = FlatIterator([1, 2, 3])
488        >>> other = FlatIterator([4, 5, 6])
489        >>> async for item in iterator.union(other):
490                print(item)
491        # 1
492        # 2
493        # 3
494        # 4
495        # 5
496        # 6
497
498        Parameters
499        ----------
500        other: `FlatIterator[Item]`
501            The iterable to union with.
502
503        Raises
504        ------
505        `StopIteration`
506            If no elements are left in the iterator.
507        """
508        return FlatIterator(itertools.chain(self._items, other))
509
510    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
511        """Calls the function on each item in the iterator.
512
513        Example
514        -------
515        >>> iterator = FlatIterator([1, 2, 3])
516        >>> iterator.for_each(lambda item: print(item))
517        # 1
518        # 2
519        # 3
520
521        Parameters
522        ----------
523        func: `typeshed.Callable[[Item], None]`
524            The function to call on each item in the iterator.
525        """
526        for item in self:
527            func(item)
528
529    def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]:
530        """Returns a new iterator that yields tuples of the index and item.
531
532        Example
533        -------
534        >>> iterator = FlatIterator([1, 2, 3])
535        >>> async for index, item in iterator.enumerate():
536                print(index, item)
537
538        # 0, 1
539        # 1, 2
540        # 2, 3
541
542        Raises
543        ------
544        `StopIteration`
545            If no elements are left in the iterator.
546        """
547        return FlatIterator(enumerate(self._items, start=start))
548
549    def _ok(self) -> typing.NoReturn:
550        raise StopIteration("No more items in the iterator.") from None
551
552    def __getitem__(self, index: int) -> Item:
553        try:
554            return self.skip(index).first()
555        except IndexError:
556            self._ok()
557
558    # This is a never.
559    def __setitem__(self) -> typing.NoReturn:
560        raise TypeError(
561            f"{type(self).__name__} doesn't support item assignment."
562        ) from None
563
564    def __repr__(self) -> str:
565        return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>'
566
567    def __len__(self) -> int:
568        return self.count()
569
570    # We support both sync and async iter.
571    def __iter__(self) -> FlatIterator[Item]:
572        return self
573
574    def __aiter__(self) -> FlatIterator[Item]:
575        return self
576
577    def __next__(self) -> Item:
578        try:
579            item = next(self._items)
580        except StopIteration:
581            self._ok()
582
583        return item
584
585    async def __anext__(self) -> Item:
586        try:
587            item = next(self._items)
588        except StopIteration as e:
589            raise StopAsyncIteration from e
590
591        return item

A Flat, In-Memory iterator for sequenced based data.

This can either be used sync or asynchronously.

Example
iterator = FlatIterator([1, 2, 3])

# Limit the results to 2.
async for item in iterator.take(2):
    print(item)
# 1
# 2

# Filter the results.
async for item in iterator.filter(lambda item: item > 1):
    print(item)
    print(iterator.count())
# 2
# 3
# 3

# Map the results.
async for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# This also works synchronously.
iterator = FlatIterator(["Hello", "World", "!"])
for item in iterator.discard(lambda item: "!" in item):
    print(item)
# Hello
# World

# Indexing is also supported.

print(iterator[0])
# Hello
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
FlatIterator(items: collections.abc.Iterable[~Item])
94    def __init__(self, items: collections.Iterable[Item]) -> None:
95        self._items = iter(items)
def collect( self, casting: 'typing.Optional[_B]' = None) -> 'typing.Union[list[Item], list[_B]]':
123    def collect(
124        self, casting: typing.Optional[_B] = None
125    ) -> typing.Union[list[Item], list[_B]]:
126        """Collects all items in the iterator into a list.
127
128        Example
129        -------
130        >>> iterator = FlatIterator([1, 2, 3])
131        >>> iterator.collect()
132        [1, 2, 3]
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        if casting is not None:
140            return typing.cast(list[_B], list(map(casting, self._items)))
141
142        return list(self._items)

Collects all items in the iterator into a list.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect()
[1, 2, 3]
Raises
  • StopIteration: If no elements are left in the iterator.
def next(self) -> ~Item:
144    def next(self) -> Item:
145        """Returns the next item in the iterator.
146
147        Example
148        -------
149        >>> iterator = FlatIterator[str](["1", "2", "3"])
150        item = iterator.next()
151        assert item == "1"
152        item = iterator.next()
153        assert item == "2"
154
155        Raises
156        ------
157        `StopIteration`
158            If no elements are left in the iterator.
159        """
160        try:
161            return self.__next__()
162        except StopIteration:
163            self._ok()

Returns the next item in the iterator.

Example
>>> iterator = FlatIterator[str](["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'FlatIterator[OtherItem]':
165    def map(
166        self, predicate: collections.Callable[[Item], OtherItem]
167    ) -> FlatIterator[OtherItem]:
168        """Maps each item in the iterator to its predicated value.
169
170        Example
171        -------
172        >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
173        <FlatIterator([1, 2, 3])>
174        >>> async for item in iterator:
175                assert isinstance(item, int)
176
177        Parameters
178        ----------
179        predicate: `collections.Callable[[Item], Item]`
180            The function to map each item in the iterator to its predicated value.
181
182        Raises
183        ------
184        `StopIteration`
185            If no elements are left in the iterator.
186        """
187        return FlatIterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
>>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
<FlatIterator([1, 2, 3])>
>>> async for item in iterator:
        assert isinstance(item, int)
Parameters
  • predicate (collections.Callable[[Item], Item]): The function to map each item in the iterator to its predicated value.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> aiobungie.FlatIterator[~Item]:
189    def take(self, n: int) -> FlatIterator[Item]:
190        """Take the first number of items until the number of items are yielded or
191        the end of the iterator is reached.
192
193        Example
194        -------
195        >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
196        >>> async for mode in iterator.take(2):
197                assert mode in [GameMode.RAID, GameMode.STRIKE]
198        <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
199
200        Parameters
201        ----------
202        n: `int`
203            The number of items to take.
204
205        Raises
206        ------
207        `StopIteration`
208            If no elements are left in the iterator.
209        """
210        return FlatIterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
>>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
>>> async for mode in iterator.take(2):
        assert mode in [GameMode.RAID, GameMode.STRIKE]
<FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
212    def take_while(
213        self, predicate: collections.Callable[[Item], bool]
214    ) -> FlatIterator[Item]:
215        """Yields items from the iterator while predicate returns `True`.
216
217        Example
218        -------
219        ```py
220        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
221
222        async for platform in (
223            iterator
224            .take_while(lambda platform: platform is not MembershipType.XBOX)
225        ):
226                print(platform)
227        # <FlatIterator([MembershipType.STEAM])>
228        ```
229
230        Parameters
231        ----------
232        predicate: `collections.Callable[[Item], bool]`
233            The function to predicate each item in the iterator.
234
235        Raises
236        ------
237        `StopIteration`
238            If no elements are left in the iterator.
239        """
240        return FlatIterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])

async for platform in (
    iterator
    .take_while(lambda platform: platform is not MembershipType.XBOX)
):
        print(platform)
# <FlatIterator([MembershipType.STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
242    def drop_while(
243        self, predicate: collections.Callable[[Item], bool]
244    ) -> FlatIterator[Item]:
245        """Yields items from the iterator while predicate returns `False`.
246
247        Example
248        -------
249        ```py
250        iterator = FlatIterator(
251            [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
252        )
253
254        async for membership in (
255            iterator
256            .drop_while(lambda membership: membership.name is not "Jim")
257        ):
258                print(membership)
259        # <FlatIterator([DestinyMembership(name="Bob")])>
260        ```
261
262        Parameters
263        ----------
264        predicate: `collections.Callable[[Item], bool]`
265            The function to predicate each item in the iterator.
266
267        Raises
268        ------
269        `StopIteration`
270            If no elements are left in the iterator.
271        """
272        return FlatIterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = FlatIterator(
    [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
)

async for membership in (
    iterator
    .drop_while(lambda membership: membership.name is not "Jim")
):
        print(membership)
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
274    def filter(
275        self, predicate: collections.Callable[[Item], bool]
276    ) -> FlatIterator[Item]:
277        """Filters the iterator to only yield items that match the predicate.
278
279        Example
280        -------
281        ```py
282        activities = FlatIterator(
283            [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
284            # Assuming Raid is solo, Strike is flawless.
285        )
286
287        async for activity in (
288            activities
289            .filter(lambda activity: activity.is_solo or activity.is_flawless)
290        ):
291                print(member)
292        # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
293        ```
294        """
295        return FlatIterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
activities = FlatIterator(
    [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
    # Assuming Raid is solo, Strike is flawless.
)

async for activity in (
    activities
    .filter(lambda activity: activity.is_solo or activity.is_flawless)
):
        print(member)
# <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
def skip(self, n: int) -> aiobungie.FlatIterator[~Item]:
297    def skip(self, n: int) -> FlatIterator[Item]:
298        """Skips the first number of items in the iterator.
299
300        Example
301        -------
302        ```py
303        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
304
305        async for platform in iterator.skip(1):
306                print(platform)
307        # Skip the first item in the iterator.
308        # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
309        """
310        return FlatIterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example

```py iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])

async for platform in iterator.skip(1): print(platform)

Skip the first item in the iterator.

MembershipType.XBOX, MembershipType.STADIA])>

def discard( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
312    def discard(
313        self, predicate: collections.Callable[[Item], bool]
314    ) -> FlatIterator[Item]:
315        """Discards all elements in the iterator for which the predicate function returns true.
316
317        Example
318        -------
319        >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
320        >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
321                # Drops all memberships that are not steam.
322                print(iterator)
323        <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
324
325        Parameters
326        ----------
327        predicate: `collections.Callable[[Item], bool]`
328            The function to test each item in the iterator.
329
330        Raises
331        ------
332        `StopIteration`
333            If no elements are left in the iterator.
334        """
335        return FlatIterator(filter(lambda x: not predicate(x), self._items))

Discards all elements in the iterator for which the predicate function returns true.

Example
>>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
>>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
        # Drops all memberships that are not steam.
        print(iterator)
<FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def zip( self, other: 'FlatIterator[OtherItem]') -> 'FlatIterator[tuple[Item, OtherItem]]':
337    def zip(
338        self, other: FlatIterator[OtherItem]
339    ) -> FlatIterator[tuple[Item, OtherItem]]:
340        """Zips the iterator with another iterable.
341
342        Example
343        -------
344        >>> iterator = FlatIterator([1, 2, 3])
345        >>> other = FlatIterator([4, 5, 6])
346        >>> async for item, other_item in iterator.zip(other):
347                assert item == other_item
348        <FlatIterator([(1, 4), (2, 5), (3, 6)])>
349
350        Parameters
351        ----------
352        other: `FlatIterator[OtherItem]`
353            The iterable to zip with.
354
355        Raises
356        ------
357        `StopIteration`
358            If no elements are left in the iterator.
359        """
360        return FlatIterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item, other_item in iterator.zip(other):
        assert item == other_item
<FlatIterator([(1, 4), (2, 5), (3, 6)])>
Parameters
  • other (FlatIterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
362    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
363        """`True` if all items in the iterator match the predicate.
364
365        Example
366        -------
367        >>> iterator = FlatIterator([1, 2, 3])
368        >>> while iterator.all(lambda item: isinstance(item, int)):
369                print("Still all integers")
370                continue
371            # Still all integers
372
373        Parameters
374        ----------
375        predicate: `collections.Callable[[Item], bool]`
376            The function to test each item in the iterator.
377
378        Raises
379        ------
380        `StopIteration`
381            If no elements are left in the iterator.
382        """
383        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> while iterator.all(lambda item: isinstance(item, int)):
        print("Still all integers")
        continue
    # Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
385    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
386        """`True` if any items in the iterator match the predicate.
387
388        Example
389        -------
390        >>> iterator = FlatIterator([1, 2, 3])
391        >>> if iterator.any(lambda item: isinstance(item, int)):
392                print("At least one item is an int.")
393        # At least one item is an int.
394
395        Parameters
396        ----------
397        predicate: `collections.Callable[[Item], bool]`
398            The function to test each item in the iterator.
399
400        Raises
401        ------
402        `StopIteration`
403            If no elements are left in the iterator.
404        """
405        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> if iterator.any(lambda item: isinstance(item, int)):
        print("At least one item is an int.")
<h1 id="at-least-one-item-is-an-int">At least one item is an int.</h1>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> aiobungie.FlatIterator[~Item]:
407    def sort(
408        self,
409        *,
410        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
411        reverse: bool = False,
412    ) -> FlatIterator[Item]:
413        """Sorts the iterator.
414
415        Example
416        -------
417        >>> iterator = FlatIterator([3, 1, 6, 7])
418        >>> async for item in iterator.sort(key=lambda item: item < 3):
419                print(item)
420        # 1
421        # 3
422        # 6
423        # 7
424
425        Parameters
426        ----------
427        key: `collections.Callable[[Item], Any]`
428            The function to sort by.
429        reverse: `bool`
430            Whether to reverse the sort.
431
432        Raises
433        ------
434        `StopIteration`
435            If no elements are left in the iterator.
436        """
437        return FlatIterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.sort(key=lambda item: item < 3):
        print(item)
<h1 id="1">1</h1>

3

6

7

Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
439    def first(self) -> Item:
440        """Returns the first item in the iterator.
441
442        Example
443        -------
444        >>> iterator = FlatIterator([3, 1, 6, 7])
445        >>> iterator.first()
446        3
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return self.take(1).next()

Returns the first item in the iterator.

Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> iterator.first()
3
Raises
  • StopIteration: If no elements are left in the iterator.
def reversed(self) -> aiobungie.FlatIterator[~Item]:
455    def reversed(self) -> FlatIterator[Item]:
456        """Returns a new iterator that yields the items in the iterator in reverse order.
457
458        Example
459        -------
460        >>> iterator = FlatIterator([3, 1, 6, 7])
461        >>> async for item in iterator.reversed():
462                print(item)
463        # 7
464        # 6
465        # 1
466        # 3
467
468        Raises
469        ------
470        `StopIteration`
471            If no elements are left in the iterator.
472        """
473        return FlatIterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.reversed():
        print(item)
<h1 id="7">7</h1>

6

1

3

Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
475    def count(self) -> int:
476        count = 0
477        for _ in self:
478            count += 1
479
480        return count
def union( self, other: aiobungie.FlatIterator[~Item]) -> aiobungie.FlatIterator[~Item]:
482    def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
483        """Returns a new iterator that yields all items from both iterators.
484
485        Example
486        -------
487        >>> iterator = FlatIterator([1, 2, 3])
488        >>> other = FlatIterator([4, 5, 6])
489        >>> async for item in iterator.union(other):
490                print(item)
491        # 1
492        # 2
493        # 3
494        # 4
495        # 5
496        # 6
497
498        Parameters
499        ----------
500        other: `FlatIterator[Item]`
501            The iterable to union with.
502
503        Raises
504        ------
505        `StopIteration`
506            If no elements are left in the iterator.
507        """
508        return FlatIterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item in iterator.union(other):
        print(item)
<h1 id="1">1</h1>

2

3

4

5

6

Parameters
  • other (FlatIterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
510    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
511        """Calls the function on each item in the iterator.
512
513        Example
514        -------
515        >>> iterator = FlatIterator([1, 2, 3])
516        >>> iterator.for_each(lambda item: print(item))
517        # 1
518        # 2
519        # 3
520
521        Parameters
522        ----------
523        func: `typeshed.Callable[[Item], None]`
524            The function to call on each item in the iterator.
525        """
526        for item in self:
527            func(item)

Calls the function on each item in the iterator.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.for_each(lambda item: print(item))
<h1 id="1">1</h1>

2

3

Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> aiobungie.FlatIterator[tuple[int, ~Item]]:
529    def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]:
530        """Returns a new iterator that yields tuples of the index and item.
531
532        Example
533        -------
534        >>> iterator = FlatIterator([1, 2, 3])
535        >>> async for index, item in iterator.enumerate():
536                print(index, item)
537
538        # 0, 1
539        # 1, 2
540        # 2, 3
541
542        Raises
543        ------
544        `StopIteration`
545            If no elements are left in the iterator.
546        """
547        return FlatIterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> async for index, item in iterator.enumerate():
        print(index, item)

0, 1

1, 2

2, 3

Raises
  • StopIteration: If no elements are left in the iterator.
@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
133@attrs.define(auto_exc=True)
134class Forbidden(HTTPException):
135    """Exception that's raised for when status code 403 occurs."""
136
137    http_status: http.HTTPStatus = attrs.field(
138        default=http.HTTPStatus.FORBIDDEN, init=False
139    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
274@typing.final
275class GameMode(int, Enum):
276    """An Enum for all available gamemodes in Destiny 2."""
277
278    NONE = 0
279    STORY = 2
280    STRIKE = 3
281    RAID = 4
282    ALLPVP = 5
283    PATROL = 6
284    ALLPVE = 7
285    RESERVED9 = 9
286    CONTROL = 10
287    RESERVED11 = 11
288    CLASH = 12
289    RESERVED13 = 13
290    CRIMSONDOUBLES = 15
291    NIGHTFALL = 16
292    HEROICNIGHTFALL = 17
293    ALLSTRIKES = 18
294    IRONBANNER = 19
295    RESERVED20 = 20
296    RESERVED21 = 21
297    RESERVED22 = 22
298    RESERVED24 = 24
299    ALLMAYHEM = 25
300    RESERVED26 = 26
301    RESERVED27 = 27
302    RESERVED28 = 28
303    RESERVED29 = 29
304    RESERVED30 = 30
305    SUPREMACY = 31
306    PRIVATEMATCHESALL = 32
307    SURVIVAL = 37
308    COUNTDOWN = 38
309    TRIALSOFTHENINE = 39
310    SOCIAL = 40
311    TRIALSCOUNTDOWN = 41
312    TRIALSSURVIVAL = 42
313    IRONBANNERCONTROL = 43
314    IRONBANNERCLASH = 44
315    IRONBANNERSUPREMACY = 45
316    SCOREDNIGHTFALL = 46
317    SCOREDHEROICNIGHTFALL = 47
318    RUMBLE = 48
319    ALLDOUBLES = 49
320    DOUBLES = 50
321    PRIVATEMATCHESCLASH = 51
322    PRIVATEMATCHESCONTROL = 52
323    PRIVATEMATCHESSUPREMACY = 53
324    PRIVATEMATCHESCOUNTDOWN = 54
325    PRIVATEMATCHESSURVIVAL = 55
326    PRIVATEMATCHESMAYHEM = 56
327    PRIVATEMATCHESRUMBLE = 57
328    HEROICADVENTURE = 58
329    SHOWDOWN = 59
330    LOCKDOWN = 60
331    SCORCHED = 61
332    SCORCHEDTEAM = 62
333    GAMBIT = 63
334    ALLPVECOMPETITIVE = 64
335    BREAKTHROUGH = 65
336    BLACKARMORYRUN = 66
337    SALVAGE = 67
338    IRONBANNERSALVAGE = 68
339    PVPCOMPETITIVE = 69
340    PVPQUICKPLAY = 70
341    CLASHQUICKPLAY = 71
342    CLASHCOMPETITIVE = 72
343    CONTROLQUICKPLAY = 73
344    CONTROLCOMPETITIVE = 74
345    GAMBITPRIME = 75
346    RECKONING = 76
347    MENAGERIE = 77
348    VEXOFFENSIVE = 78
349    NIGHTMAREHUNT = 79
350    ELIMINATION = 80
351    MOMENTUM = 81
352    DUNGEON = 82
353    SUNDIAL = 83
354    TRIALS_OF_OSIRIS = 84
355    DARES = 85
356    OFFENSIVE = 86
357    LOSTSECTOR = 87
358    RIFT = 88
359    ZONECONTROL = 89
360    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
58@typing.final
59class GatingScope(int, enums.Enum):
60    """An enum represents restrictive type of gating that is being performed by an entity.
61
62    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
63    applies to everyone equally, or to their specific Profile or Character states.
64    """
65
66    NONE = 0
67    GLOBAL = 1
68    CLAN = 2
69    PROFILE = 3
70    CHARACTER = 4
71    ITEM = 5
72    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
487@typing.final
488class Gender(int, Enum):
489    """An Enum for Destiny Genders."""
490
491    MALE = 0
492    FEMALE = 1
493    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
656@typing.final
657class GroupType(int, Enum):
658    """An enums for the known bungie group types."""
659
660    GENERAL = 0
661    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
65@attrs.define(auto_exc=True)
66class HTTPError(AiobungieError):
67    """Exception base used for HTTP request errors."""
68
69    message: str
70    """The error message."""
71
72    http_status: http.HTTPStatus
73    """The response status."""

Exception base used for HTTP request errors.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
args
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 86@attrs.define(auto_exc=True, kw_only=True)
 87class HTTPException(HTTPError):
 88    """Exception base internally used for an HTTP request response errors."""
 89
 90    error_code: int
 91    """The returned Bungie error status code."""
 92
 93    http_status: http.HTTPStatus
 94    """The request response http status."""
 95
 96    throttle_seconds: int
 97    """The Bungie response throttle seconds."""
 98
 99    url: typing.Optional[typedefs.StrOrURL]
100    """The URL/endpoint caused this error."""
101
102    body: typing.Any
103    """The response body."""
104
105    headers: multidict.CIMultiDictProxy[str]
106    """The response headers."""
107
108    message: str
109    """A Bungie human readable message describes the cause of the error."""
110
111    error_status: str
112    """A Bungie short error status describes the cause of the error."""
113
114    message_data: dict[str, str]
115    """A dict of string key, value that includes each cause of the error
116    to a message describes information about that error.
117    """
118
119    def __str__(self) -> str:
120        if self.message:
121            message_body = self.message
122
123        if self.error_status:
124            error_status_body = self.error_status
125
126        return (
127            f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: "
128            f"Error status: {error_status_body}, Error message: {message_body} from {self.url} "
129            f"{str(self.body)}"
130        )

Exception base internally used for an HTTP request response errors.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
args
class Image:
 72class Image:
 73    """Representation of an image/avatar/picture at Bungie.
 74
 75    Example
 76    -------
 77    ```py
 78    from aiobungie import Image
 79    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 80    print(img)
 81    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 82
 83    # Stream the image.
 84    async for chunk in img:
 85        # Byte chunks of the image.
 86        print(chunk)
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image. If `None`, the default missing image path will be used.
 96    """
 97
 98    __slots__ = ("_path",)
 99
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
102
103    @property
104    def is_missing(self) -> bool:
105        return not self._path
106
107    @property
108    def url(self) -> str:
109        """The URL to the image."""
110        return self.create_url()
111
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"
116
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
126
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err
181
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader
204
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk
224
225    def __repr__(self) -> str:
226        return f"Image(url={self.create_url()})"
227
228    def __str__(self) -> str:
229        return self.create_url()
230
231    def __aiter__(self) -> Image:
232        return self
233
234    async def __anext__(self) -> bytes:
235        return await self.read()
236
237    def __await__(self) -> collections.Generator[None, None, bytes]:
238        return self.__anext__().__await__()

Representation of an image/avatar/picture at Bungie.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Stream the image.
async for chunk in img:
    # Byte chunks of the image.
    print(chunk)

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image. If None, the default missing image path will be used.
Image(path: Optional[str] = None)
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
is_missing: bool
url: str

The URL to the image.

@staticmethod
def missing_path() -> str:
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

def create_url(self) -> str:
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: Union[pathlib.Path, str], /, mime_type: Union[aiobungie.internal.assets.MimeType, str, NoneType] = None) -> None:
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): Optional MIME type of the image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
203@attrs.define(auto_exc=True)
204class InternalServerError(HTTPException):
205    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
722@typing.final
723class ItemBindStatus(int, Enum):
724    """An enum for Destiny 2 items bind status."""
725
726    NOT_BOUND = 0
727    BOUND_TO_CHARACTER = 1
728    BOUND_TO_ACCOUNT = 2
729    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
732@typing.final
733class ItemLocation(int, Enum):
734    """An enum for Destiny 2 items location."""
735
736    UNKNOWN = 0
737    INVENTORY = 1
738    VAULT = 2
739    VENDOR = 3
740    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
757@typing.final
758class ItemState(Flag):
759    """An enum for Destiny 2 item states."""
760
761    NONE = 0
762    LOCKED = 1
763    TRACKED = 2
764    MASTERWORKED = 4
765    CRAFTED = 8
766    """If this bit is set, the item has been 'crafted' by the player."""
767    HIGHLITED_OBJECTIVE = 16
768    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
589@typing.final
590class ItemSubType(int, Enum):
591    """An enum for Destiny 2 inventory items subtype."""
592
593    NONE = 0
594    AUTORIFLE = 6
595    SHOTGUN = 7
596    MACHINEGUN = 8
597    HANDCANNON = 9
598    ROCKETLAUNCHER = 10
599    FUSIONRIFLE = 11
600    SNIPERRIFLE = 12
601    PULSERIFLE = 13
602    SCOUTRIFLE = 14
603    SIDEARM = 17
604    SWORD = 18
605    MASK = 19
606    SHADER = 20
607    ORNAMENT = 21
608    FUSIONRIFLELINE = 22
609    GRENADELAUNCHER = 23
610    SUBMACHINEGUN = 24
611    TRACERIFLE = 25
612    HELMETARMOR = 26
613    GAUNTLETSARMOR = 27
614    CHESTARMOR = 28
615    LEGARMOR = 29
616    CLASSARMOR = 30
617    BOW = 31
618    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
621@typing.final
622class ItemTier(int, Enum):
623    """An enum for a Destiny 2 item tier."""
624
625    NONE = 0
626    BASIC = 3340296461
627    COMMON = 2395677314
628    RARE = 2127292149
629    LEGENDERY = 4008398120
630    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
556@typing.final
557class ItemType(int, Enum):
558    """Enums for Destiny2's item types."""
559
560    NONE = 0
561    CURRENCY = 1
562    ARMOR = 2
563    WEAPON = 3
564    MESSAGE = 7
565    ENGRAM = 8
566    CONSUMABLE = 9
567    EXCHANGEMATERIAL = 10
568    MISSIONREWARD = 11
569    QUESTSTEP = 12
570    QUESTSTEPCOMPLETE = 13
571    EMBLEM = 14
572    QUEST = 15
573    SUBCLASS = 16
574    CLANBANNER = 17
575    AURA = 18
576    MOD = 19
577    DUMMY = 20
578    SHIP = 21
579    VEHICLE = 22
580    EMOTE = 23
581    GHOST = 24
582    PACKAGE = 25
583    BOUNTY = 26
584    WRAPPER = 27
585    SEASONALARTIFACT = 28
586    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
713@typing.final
714class MembershipOption(int, Enum):
715    """A enum for GroupV2 membership options."""
716
717    REVIEWD = 0
718    OPEN = 1
719    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
463@typing.final
464class MembershipType(int, Enum):
465    """An Enum for Bungie membership types."""
466
467    NONE = 0
468    XBOX = 1
469    PSN = 2
470    STEAM = 3
471    BLIZZARD = 4
472    STADIA = 5
473    BUNGIE = 254
474    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
176@attrs.define(auto_exc=True)
177class MembershipTypeError(BadRequest):
178    """A bad request error raised when passing wrong membership to the request.
179
180    Those fields are useful since it returns the correct membership and id which can be used
181    to make the request again with those fields.
182    """
183
184    membership_type: str = attrs.field(default="")
185    """The errored membership type passed to the request."""
186
187    membership_id: int = attrs.field(default=0)
188    """The errored user's membership id."""
189
190    required_membership: str = attrs.field(default="")
191    """The required correct membership for errored user."""
192
193    def __str__(self) -> str:
194        return (
195            f"Expected membership: {self.required_membership}, "
196            f"But got {self.membership_type} for id {self.membership_id}"
197        )
198
199    def __int__(self) -> int:
200        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>, membership_type: str = '', membership_id: int = 0, required_membership: str = '')
 2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = http_status
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
args
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
506@typing.final
507class MilestoneType(int, Enum):
508    """An Enum for Destiny 2 milestone types."""
509
510    UNKNOWN = 0
511    TUTORIAL = 1
512    ONETIME = 2
513    WEEKLY = 3
514    DAILY = 4
515    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
142@attrs.define(auto_exc=True)
143class NotFound(HTTPException):
144    """Raised when an unknown request was not found."""
145
146    http_status: http.HTTPStatus = attrs.field(
147        default=http.HTTPStatus.NOT_FOUND, init=False
148    )

Raised when an unknown request was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 94@typing.final
 95class ObjectiveUIStyle(int, enums.Enum):
 96    NONE = 0
 97    HIGHLIGHTED = 1
 98    CRAFTING_WEAPON_LEVEL = 2
 99    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
100    CRAFTING_WEAPON_TIMESTAMP = 4
101    CRAFTING_MEMENTOS = 5
102    CRAFTING_MEMENTO_TITLE = 6

An enumeration.

NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
235@typing.final
236class Place(int, Enum):
237    """An Enum for Destiny 2 Places and NOT Planets"""
238
239    ORBIT = 2961497387
240    SOCIAL = 4151112093
241    LIGHT_HOUSE = 4276116472
242    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
200@typing.final
201class Planet(int, Enum):
202    """An Enum for all available planets in Destiny 2."""
203
204    UNKNOWN = 0
205    """Unknown space"""
206
207    EARTH = 3747705955
208    """Earth"""
209
210    DREAMING_CITY = 2877881518
211    """The Dreaming city."""
212
213    NESSUS = 3526908984
214    """Nessus"""
215
216    MOON = 3325508439
217    """The Moon"""
218
219    COSMODROME = 3990611421
220    """The Cosmodrome"""
221
222    TANGLED_SHORE = 3821439926
223    """The Tangled Shore"""
224
225    VENUS = 3871070152
226    """Venus"""
227
228    EAZ = 541863059  # Exclusive event.
229    """European Aerial Zone"""
230
231    EUROPA = 1729879943
232    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
683@typing.final
684class Presence(int, Enum):
685    """An enum for a bungie friend status."""
686
687    OFFLINE_OR_UNKNOWN = 0
688    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
771@typing.final
772class PrivacySetting(int, Enum):
773    """An enum for players's privacy settings."""
774
775    OPEN = 0
776    CLAN_AND_FRIENDS = 1
777    FRIENDS_ONLY = 2
778    INVITE_ONLY = 3
779    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 350class RESTClient(interfaces.RESTInterface):
 351    """A RESTful client implementation for Bungie's API.
 352
 353    This client is designed to only make HTTP requests and return JSON objects
 354    to provide RESTful functionality.
 355
 356    This client is also used within `aiobungie.Client` which deserialize those returned JSON objects
 357    using the factory into Pythonic data classes objects which provide Python functionality.
 358
 359    Example
 360    -------
 361    ```py
 362    import aiobungie
 363
 364    async def main():
 365        async with aiobungie.RESTClient("TOKEN") as rest_client:
 366            req = await rest_client.fetch_clan_members(4389205)
 367            clan_members = req['results']
 368            for member in clan_members:
 369                for k, v in member['destinyUserInfo'].items():
 370                    print(k, v)
 371    ```
 372
 373    Parameters
 374    ----------
 375    token : `str`
 376        A valid application token from Bungie's developer portal.
 377
 378    Other Parameters
 379    ----------------
 380    max_retries : `int`
 381        The max retries number to retry if the request hit a `5xx` status code.
 382    max_ratelimit_retries : `int`
 383        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
 384    client_secret : `typing.Optional[str]`
 385        An optional application client secret,
 386        This is only needed if you're fetching OAuth2 tokens with this client.
 387    client_id : `typing.Optional[int]`
 388        An optional application client id,
 389        This is only needed if you're fetching OAuth2 tokens with this client.
 390    enable_debugging : `bool | str`
 391        Whether to enable logging responses or not.
 392
 393    Logging Levels
 394    --------------
 395    * `False`: This will disable logging.
 396    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 397    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 398    """
 399
 400    __slots__ = (
 401        "_token",
 402        "_session",
 403        "_lock",
 404        "_max_retries",
 405        "_client_secret",
 406        "_client_id",
 407        "_metadata",
 408        "_max_rate_limit_retries",
 409    )
 410
 411    def __init__(
 412        self,
 413        token: str,
 414        /,
 415        client_secret: typing.Optional[str] = None,
 416        client_id: typing.Optional[int] = None,
 417        *,
 418        max_retries: int = 4,
 419        max_ratelimit_retries: int = 3,
 420        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 421    ) -> None:
 422        self._session: typing.Optional[_Session] = None
 423        self._lock: typing.Optional[asyncio.Lock] = None
 424        self._client_secret = client_secret
 425        self._client_id = client_id
 426        self._token: str = token
 427        self._max_retries = max_retries
 428        self._max_rate_limit_retries = max_ratelimit_retries
 429        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 430
 431        self._set_debug_level(enable_debugging)
 432
 433    @property
 434    def client_id(self) -> typing.Optional[int]:
 435        return self._client_id
 436
 437    @property
 438    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 439        return self._metadata
 440
 441    @property
 442    def is_alive(self) -> bool:
 443        return self._session is not None
 444
 445    @typing.final
 446    async def close(self) -> None:
 447        if self._session is not None:
 448            await self._session.close()
 449            self._session = None
 450
 451    @typing.final
 452    def enable_debugging(
 453        self,
 454        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 455        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 456        /,
 457    ) -> None:
 458        self._set_debug_level(level, file)
 459
 460    @typing.final
 461    async def static_request(
 462        self,
 463        method: typing.Union[RequestMethod, str],
 464        path: str,
 465        *,
 466        auth: typing.Optional[str] = None,
 467        json: typing.Optional[dict[str, typing.Any]] = None,
 468    ) -> ResponseSig:
 469        return await self._request(method, path, auth=auth, json=json)
 470
 471    @typing.final
 472    def build_oauth2_url(
 473        self, client_id: typing.Optional[int] = None
 474    ) -> typing.Optional[str]:
 475        client_id = client_id or self._client_id
 476        if client_id is None:
 477            return None
 478
 479        return url.OAUTH2_EP_BUILDER.format(
 480            oauth_endpoint=url.OAUTH_EP,
 481            client_id=client_id,
 482            uuid=_uuid(),
 483        )
 484
 485    def _open(self) -> _Session:
 486        """Open a new client session. This is called internally with contextmanager usage."""
 487        asyncio.get_running_loop()
 488        if self._session is None:
 489            self._session = _Session.create(
 490                owner=False,
 491                raise_status=False,
 492                connect=None,
 493                socket_read=None,
 494                socket_connect=None,
 495            )
 496        return self._session
 497
 498    @staticmethod
 499    def _set_debug_level(
 500        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 501        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 502    ) -> None:
 503
 504        file_handler = logging.FileHandler(file, mode="w") if file else None
 505        if level == "TRACE" or level == TRACE:
 506            logging.basicConfig(
 507                level=TRACE, handlers=[file_handler] if file_handler else None
 508            )
 509
 510        elif level:
 511            logging.basicConfig(
 512                level=logging.DEBUG, handlers=[file_handler] if file_handler else None
 513            )
 514
 515    async def _request(
 516        self,
 517        method: typing.Union[RequestMethod, str],
 518        route: str,
 519        *,
 520        base: bool = False,
 521        oauth2: bool = False,
 522        auth: typing.Optional[str] = None,
 523        unwrapping: typing.Literal["json", "read"] = "json",
 524        json: typing.Optional[dict[str, typing.Any]] = None,
 525        headers: typing.Optional[dict[str, typing.Any]] = None,
 526        data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None,
 527    ) -> ResponseSig:
 528
 529        retries: int = 0
 530        session = self._open()
 531        headers = headers or {}
 532
 533        headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT)
 534        headers["X-API-KEY"] = self._token
 535
 536        if auth is not None:
 537            headers[_AUTH_HEADER] = f"Bearer {auth}"
 538
 539        # Handling endpoints
 540        endpoint = url.BASE
 541
 542        if not base:
 543            endpoint = endpoint + url.REST_EP
 544
 545        if oauth2:
 546            headers["Content-Type"] = "application/x-www-form-urlencoded"
 547            endpoint = endpoint + url.TOKEN_EP
 548
 549        if self._lock is None:
 550            self._lock = asyncio.Lock()
 551
 552        while True:
 553            try:
 554                async with (stack := contextlib.AsyncExitStack()):
 555                    await stack.enter_async_context(self._lock)
 556
 557                    # We make the request here.
 558                    taken_time = time.monotonic()
 559                    response = await stack.enter_async_context(
 560                        session.client_session.request(
 561                            method=method,
 562                            url=f"{endpoint}/{route}",
 563                            json=json,
 564                            headers=headers,
 565                            data=data,
 566                        )
 567                    )
 568                    response_time = (time.monotonic() - taken_time) * 1_000
 569
 570                    _LOG.debug(
 571                        "%s %s %s Time %.4fms",
 572                        method,
 573                        f"{endpoint}/{route}",
 574                        f"{response.status} {response.reason}",
 575                        response_time,
 576                    )
 577
 578                    await self._handle_ratelimit(
 579                        response, method, route, self._max_rate_limit_retries
 580                    )
 581
 582                    if response.status == http.HTTPStatus.NO_CONTENT:
 583                        return None
 584
 585                    if 300 > response.status >= 200:
 586                        if unwrapping == "read":
 587                            # We need to read the bytes for the manifest response.
 588                            return await response.read()
 589
 590                        if response.content_type == _APP_JSON:
 591                            json_data = await response.json()
 592
 593                            _LOG.debug(
 594                                "%s %s %s Time %.4fms",
 595                                method,
 596                                f"{endpoint}/{route}",
 597                                f"{response.status} {response.reason}",
 598                                response_time,
 599                            )
 600
 601                            if _LOG.isEnabledFor(TRACE):
 602                                headers.update(response.headers)
 603
 604                                _LOG.log(
 605                                    TRACE,
 606                                    "%s",
 607                                    error.stringify_http_message(headers),
 608                                )
 609
 610                            # Return the response.
 611                            # oauth2 responses are not packed inside a Response object.
 612                            if oauth2:
 613                                return json_data  # type: ignore[no-any-return]
 614
 615                            return json_data["Response"]  # type: ignore[no-any-return]
 616
 617                    if (
 618                        response.status in _RETRY_5XX
 619                        and retries < self._max_retries  # noqa: W503
 620                    ):
 621                        backoff_ = backoff.ExponentialBackOff(maximum=6)
 622                        sleep_time = next(backoff_)
 623                        _LOG.warning(
 624                            "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 625                            response.status,
 626                            response.reason,
 627                            sleep_time,
 628                            self._max_retries - retries,
 629                        )
 630
 631                        retries += 1
 632                        await asyncio.sleep(sleep_time)
 633                        continue
 634
 635                    raise await error.raise_error(response)
 636            # eol
 637            except _Dyn:
 638                continue
 639
 640    if not typing.TYPE_CHECKING:
 641
 642        def __enter__(self) -> typing.NoReturn:
 643            cls = type(self)
 644            raise TypeError(
 645                f"{cls.__qualname__} is async only, use 'async with' instead."
 646            )
 647
 648        def __exit__(
 649            self,
 650            exception_type: typing.Optional[type[BaseException]],
 651            exception: typing.Optional[BaseException],
 652            exception_traceback: typing.Optional[types.TracebackType],
 653        ) -> None:
 654            ...
 655
 656    async def __aenter__(self) -> RESTClient:
 657        self._open()
 658        return self
 659
 660    async def __aexit__(
 661        self,
 662        exception_type: typing.Optional[type[BaseException]],
 663        exception: typing.Optional[BaseException],
 664        exception_traceback: typing.Optional[types.TracebackType],
 665    ) -> None:
 666        await self.close()
 667
 668    # We don't want this to be super complicated.
 669    @staticmethod
 670    @typing.final
 671    async def _handle_ratelimit(
 672        response: aiohttp.ClientResponse,
 673        method: str,
 674        route: str,
 675        max_ratelimit_retries: int = 3,
 676    ) -> None:
 677
 678        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 679            return
 680
 681        if response.content_type != _APP_JSON:
 682            raise error.HTTPError(
 683                f"Being ratelimited on non JSON request, {response.content_type}.",
 684                http.HTTPStatus.TOO_MANY_REQUESTS,
 685            )
 686
 687        count: int = 0
 688        json: typedefs.JSONObject = await response.json()
 689        retry_after = float(json["ThrottleSeconds"])
 690
 691        while True:
 692            if count == max_ratelimit_retries:
 693                raise _Dyn
 694
 695            if retry_after <= 0:
 696                # We sleep for a little bit to avoid funky behavior.
 697                sleep_time = float(random.random() + 0.93) / 2
 698
 699                _LOG.warning(
 700                    "We're being ratelimited with method %s route %s. Sleeping for %.2fs.",
 701                    method,
 702                    route,
 703                    sleep_time,
 704                )
 705                count += 1
 706                await asyncio.sleep(sleep_time)
 707                continue
 708
 709            raise error.RateLimitedError(
 710                body=json,
 711                url=str(response.real_url),
 712                retry_after=retry_after,
 713            )
 714
 715    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 716
 717        if not isinstance(self._client_id, int):
 718            raise TypeError(
 719                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
 720            )
 721
 722        if not isinstance(self._client_secret, str):
 723            raise TypeError(
 724                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
 725            )
 726
 727        headers = {
 728            "client_secret": self._client_secret,
 729        }
 730
 731        data = (
 732            f"grant_type=authorization_code&code={code}"
 733            f"&client_id={self._client_id}&client_secret={self._client_secret}"
 734        )
 735
 736        response = await self._request(
 737            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
 738        )
 739        assert isinstance(response, dict)
 740        return builders.OAuth2Response.build_response(response)
 741
 742    async def refresh_access_token(
 743        self, refresh_token: str, /
 744    ) -> builders.OAuth2Response:
 745        if not isinstance(self._client_id, int):
 746            raise TypeError(
 747                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
 748            )
 749
 750        if not isinstance(self._client_secret, str):
 751            raise TypeError(
 752                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
 753            )
 754
 755        data = {
 756            "grant_type": "refresh_token",
 757            "refresh_token": refresh_token,
 758            "client_id": self._client_id,
 759            "client_secret": self._client_secret,
 760            "Content-Type": "application/x-www-form-urlencoded",
 761        }
 762
 763        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
 764        assert isinstance(response, dict)
 765        return builders.OAuth2Response.build_response(response)
 766
 767    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 768        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 769        resp = await self._request(
 770            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
 771        )
 772        assert isinstance(resp, dict)
 773        return resp
 774
 775    async def fetch_user_themes(self) -> typedefs.JSONArray:
 776        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 777        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
 778        assert isinstance(resp, list)
 779        return resp
 780
 781    async def fetch_membership_from_id(
 782        self,
 783        id: int,
 784        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 785        /,
 786    ) -> typedefs.JSONObject:
 787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 788        resp = await self._request(
 789            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
 790        )
 791        assert isinstance(resp, dict)
 792        return resp
 793
 794    async def fetch_player(
 795        self,
 796        name: str,
 797        code: int,
 798        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 799        /,
 800    ) -> typedefs.JSONArray:
 801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 802        resp = await self._request(
 803            RequestMethod.POST,
 804            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 805            json={"displayName": name, "displayNameCode": code},
 806        )
 807        assert isinstance(resp, list)
 808        return resp
 809
 810    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 811        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 812        resp = await self._request(
 813            RequestMethod.POST,
 814            "User/Search/GlobalName/0",
 815            json={"displayNamePrefix": name},
 816        )
 817        assert isinstance(resp, dict)
 818        return resp
 819
 820    async def fetch_clan_from_id(
 821        self, id: int, /, access_token: typing.Optional[str] = None
 822    ) -> typedefs.JSONObject:
 823        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 824        resp = await self._request(
 825            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
 826        )
 827        assert isinstance(resp, dict)
 828        return resp
 829
 830    async def fetch_clan(
 831        self,
 832        name: str,
 833        /,
 834        access_token: typing.Optional[str] = None,
 835        *,
 836        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 837    ) -> typedefs.JSONObject:
 838        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 839        resp = await self._request(
 840            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 841        )
 842        assert isinstance(resp, dict)
 843        return resp
 844
 845    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 846        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 847        resp = await self._request(
 848            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
 849        )
 850        assert isinstance(resp, dict)
 851        return resp
 852
 853    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 854        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 855        resp = await self._request(
 856            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
 857        )
 858        assert isinstance(resp, list)
 859        return resp
 860
 861    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 862        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 863        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
 864        assert isinstance(resp, dict)
 865        return resp
 866
 867    async def fetch_character(
 868        self,
 869        member_id: int,
 870        membership_type: typedefs.IntAnd[enums.MembershipType],
 871        character_id: int,
 872        components: list[enums.ComponentType],
 873        auth: typing.Optional[str] = None,
 874    ) -> typedefs.JSONObject:
 875        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 876        collector = _collect_components(components)
 877        response = await self._request(
 878            RequestMethod.GET,
 879            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 880            f"Character/{character_id}/?components={collector}",
 881            auth=auth,
 882        )
 883        assert isinstance(response, dict)
 884        return response
 885
 886    async def fetch_activities(
 887        self,
 888        member_id: int,
 889        character_id: int,
 890        mode: typedefs.IntAnd[enums.GameMode],
 891        membership_type: typedefs.IntAnd[
 892            enums.MembershipType
 893        ] = enums.MembershipType.ALL,
 894        *,
 895        page: int = 0,
 896        limit: int = 1,
 897    ) -> typedefs.JSONObject:
 898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 899        resp = await self._request(
 900            RequestMethod.GET,
 901            f"Destiny2/{int(membership_type)}/Account/"
 902            f"{member_id}/Character/{character_id}/Stats/Activities"
 903            f"/?mode={int(mode)}&count={limit}&page={page}",
 904        )
 905        assert isinstance(resp, dict)
 906        return resp
 907
 908    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 909        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 910        resp = await self._request(
 911            RequestMethod.GET,
 912            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 913        )
 914        assert isinstance(resp, dict)
 915        return resp
 916
 917    async def fetch_profile(
 918        self,
 919        membership_id: int,
 920        type: typedefs.IntAnd[enums.MembershipType],
 921        components: list[enums.ComponentType],
 922        auth: typing.Optional[str] = None,
 923    ) -> typedefs.JSONObject:
 924        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 925        collector = _collect_components(components)
 926        response = await self._request(
 927            RequestMethod.GET,
 928            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 929            auth=auth,
 930        )
 931        assert isinstance(response, dict)
 932        return response
 933
 934    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 935        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 936        response = await self._request(
 937            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
 938        )
 939        assert isinstance(response, dict)
 940        return response
 941
 942    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 943        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 944        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 945        assert isinstance(resp, dict)
 946        return resp
 947
 948    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 949        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 950        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 951        assert isinstance(resp, dict)
 952        return resp
 953
 954    async def fetch_groups_for_member(
 955        self,
 956        member_id: int,
 957        member_type: typedefs.IntAnd[enums.MembershipType],
 958        /,
 959        *,
 960        filter: int = 0,
 961        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 962    ) -> typedefs.JSONObject:
 963        resp = await self._request(
 964            RequestMethod.GET,
 965            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 966        )
 967        assert isinstance(resp, dict)
 968        return resp
 969
 970    async def fetch_potential_groups_for_member(
 971        self,
 972        member_id: int,
 973        member_type: typedefs.IntAnd[enums.MembershipType],
 974        /,
 975        *,
 976        filter: int = 0,
 977        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 978    ) -> typedefs.JSONObject:
 979        resp = await self._request(
 980            RequestMethod.GET,
 981            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 982        )
 983        assert isinstance(resp, dict)
 984        return resp
 985
 986    async def fetch_clan_members(
 987        self,
 988        clan_id: int,
 989        /,
 990        *,
 991        name: typing.Optional[str] = None,
 992        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 993    ) -> typedefs.JSONObject:
 994        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 995        resp = await self._request(
 996            RequestMethod.GET,
 997            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 998        )
 999        assert isinstance(resp, dict)
1000        return resp
1001
1002    async def fetch_hardlinked_credentials(
1003        self,
1004        credential: int,
1005        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
1006        /,
1007    ) -> typedefs.JSONObject:
1008        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1009        resp = await self._request(
1010            RequestMethod.GET,
1011            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
1012        )
1013        assert isinstance(resp, dict)
1014        return resp
1015
1016    async def fetch_user_credentials(
1017        self, access_token: str, membership_id: int, /
1018    ) -> typedefs.JSONArray:
1019        resp = await self._request(
1020            RequestMethod.GET,
1021            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
1022            auth=access_token,
1023        )
1024        assert isinstance(resp, list)
1025        return resp
1026
1027    async def insert_socket_plug(
1028        self,
1029        action_token: str,
1030        /,
1031        instance_id: int,
1032        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1033        character_id: int,
1034        membership_type: typedefs.IntAnd[enums.MembershipType],
1035    ) -> typedefs.JSONObject:
1036
1037        if isinstance(plug, builders.PlugSocketBuilder):
1038            plug = plug.collect()
1039
1040        body = {
1041            "actionToken": action_token,
1042            "itemInstanceId": instance_id,
1043            "plug": plug,
1044            "characterId": character_id,
1045            "membershipType": int(membership_type),
1046        }
1047        resp = await self._request(
1048            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1049        )
1050        assert isinstance(resp, dict)
1051        return resp
1052
1053    async def insert_socket_plug_free(
1054        self,
1055        access_token: str,
1056        /,
1057        instance_id: int,
1058        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1059        character_id: int,
1060        membership_type: typedefs.IntAnd[enums.MembershipType],
1061    ) -> typedefs.JSONObject:
1062
1063        if isinstance(plug, builders.PlugSocketBuilder):
1064            plug = plug.collect()
1065
1066        body = {
1067            "itemInstanceId": instance_id,
1068            "plug": plug,
1069            "characterId": character_id,
1070            "membershipType": int(membership_type),
1071        }
1072        resp = await self._request(
1073            RequestMethod.POST,
1074            "Destiny2/Actions/Items/InsertSocketPlugFree",
1075            json=body,
1076            auth=access_token,
1077        )
1078        assert isinstance(resp, dict)
1079        return resp
1080
1081    async def set_item_lock_state(
1082        self,
1083        access_token: str,
1084        state: bool,
1085        /,
1086        item_id: int,
1087        character_id: int,
1088        membership_type: typedefs.IntAnd[enums.MembershipType],
1089    ) -> int:
1090        body = {
1091            "state": state,
1092            "itemId": item_id,
1093            "characterId": character_id,
1094            "membership_type": int(membership_type),
1095        }
1096        response = await self._request(
1097            RequestMethod.POST,
1098            "Destiny2/Actions/Items/SetLockState",
1099            json=body,
1100            auth=access_token,
1101        )
1102        assert isinstance(response, int)
1103        return response
1104
1105    async def set_quest_track_state(
1106        self,
1107        access_token: str,
1108        state: bool,
1109        /,
1110        item_id: int,
1111        character_id: int,
1112        membership_type: typedefs.IntAnd[enums.MembershipType],
1113    ) -> int:
1114        body = {
1115            "state": state,
1116            "itemId": item_id,
1117            "characterId": character_id,
1118            "membership_type": int(membership_type),
1119        }
1120        response = await self._request(
1121            RequestMethod.POST,
1122            "Destiny2/Actions/Items/SetTrackedState",
1123            json=body,
1124            auth=access_token,
1125        )
1126        assert isinstance(response, int)
1127        return response
1128
1129    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1130        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1131        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1132        assert isinstance(path, dict)
1133        return path
1134
1135    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1136        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1137        _ensure_manifest_language(language)
1138
1139        content = await self.fetch_manifest_path()
1140        resp = await self._request(
1141            RequestMethod.GET,
1142            content["mobileWorldContentPaths"][language],
1143            unwrapping="read",
1144            base=True,
1145        )
1146        assert isinstance(resp, bytes)
1147        return resp
1148
1149    async def download_manifest(
1150        self,
1151        language: str = "en",
1152        name: str = "manifest.sqlite3",
1153        *,
1154        force: bool = False,
1155    ) -> None:
1156        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1157        if os.path.exists(name):
1158
1159            if force:
1160                _LOG.debug("Forcing manifest download.")
1161                os.remove(name)
1162
1163                return await self.download_manifest(language, name, force=force)
1164
1165            else:
1166                raise FileExistsError(
1167                    "Manifest file already exists, "
1168                    "If you want to force download, set the `force` parameter to `True`."
1169                )
1170
1171        _LOG.debug("Downloading manifest...")
1172        data_bytes = await self.read_manifest_bytes(language)
1173        await asyncio.get_running_loop().run_in_executor(
1174            None, _write_sqlite_bytes, data_bytes, name
1175        )
1176
1177    async def download_json_manifest(self, language: str = "en") -> None:
1178        _ensure_manifest_language(language)
1179
1180        _LOG.debug("Downloading manifest JSON...")
1181
1182        content = await self.fetch_manifest_path()
1183        json_bytes = await self._request(
1184            RequestMethod.GET,
1185            content["jsonWorldContentPaths"][language],
1186            unwrapping="read",
1187            base=True,
1188        )
1189
1190        await asyncio.get_running_loop().run_in_executor(
1191            None, _write_json_bytes, json_bytes
1192        )
1193        _LOG.debug("Finished downloading manifest JSON.")
1194
1195    async def fetch_manifest_version(self) -> str:
1196        return typing.cast(str, (await self.fetch_manifest_path())["version"])
1197
1198    @staticmethod
1199    @helpers.deprecated(
1200        since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect"
1201    )
1202    def connect_manifest(
1203        path: typing.Optional[pathlib.Path] = None,
1204        connection: type[sqlite3.Connection] = sqlite3.Connection,
1205    ) -> sqlite3.Connection:
1206        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1207        path = path or pathlib.Path("./manifest.sqlite3")
1208        if not path.exists():
1209            raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.")
1210        return connection(path.name)
1211
1212    async def fetch_linked_profiles(
1213        self,
1214        member_id: int,
1215        member_type: typedefs.IntAnd[enums.MembershipType],
1216        /,
1217        *,
1218        all: bool = False,
1219    ) -> typedefs.JSONObject:
1220        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1221        resp = await self._request(
1222            RequestMethod.GET,
1223            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1224        )
1225        assert isinstance(resp, dict)
1226        return resp
1227
1228    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1229        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1230        resp = await self._request(
1231            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1232        )
1233        assert isinstance(resp, dict)
1234        return resp
1235
1236    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1237        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1238        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1239        assert isinstance(resp, dict)
1240        return resp
1241
1242    async def fetch_public_milestone_content(
1243        self, milestone_hash: int, /
1244    ) -> typedefs.JSONObject:
1245        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1246        resp = await self._request(
1247            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1248        )
1249        assert isinstance(resp, dict)
1250        return resp
1251
1252    async def fetch_current_user_memberships(
1253        self, access_token: str, /
1254    ) -> typedefs.JSONObject:
1255        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1256        resp = await self._request(
1257            RequestMethod.GET,
1258            "User/GetMembershipsForCurrentUser/",
1259            auth=access_token,
1260        )
1261        assert isinstance(resp, dict)
1262        return resp
1263
1264    async def equip_item(
1265        self,
1266        access_token: str,
1267        /,
1268        item_id: int,
1269        character_id: int,
1270        membership_type: typedefs.IntAnd[enums.MembershipType],
1271    ) -> None:
1272        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1273        payload = {
1274            "itemId": item_id,
1275            "characterId": character_id,
1276            "membershipType": int(membership_type),
1277        }
1278
1279        await self._request(
1280            RequestMethod.POST,
1281            "Destiny2/Actions/Items/EquipItem/",
1282            json=payload,
1283            auth=access_token,
1284        )
1285
1286    async def equip_items(
1287        self,
1288        access_token: str,
1289        /,
1290        item_ids: list[int],
1291        character_id: int,
1292        membership_type: typedefs.IntAnd[enums.MembershipType],
1293    ) -> None:
1294        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1295        payload = {
1296            "itemIds": item_ids,
1297            "characterId": character_id,
1298            "membershipType": int(membership_type),
1299        }
1300        await self._request(
1301            RequestMethod.POST,
1302            "Destiny2/Actions/Items/EquipItems/",
1303            json=payload,
1304            auth=access_token,
1305        )
1306
1307    async def ban_clan_member(
1308        self,
1309        access_token: str,
1310        /,
1311        group_id: int,
1312        membership_id: int,
1313        membership_type: typedefs.IntAnd[enums.MembershipType],
1314        *,
1315        length: int = 0,
1316        comment: undefined.UndefinedOr[str] = undefined.Undefined,
1317    ) -> None:
1318        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1319        payload = {"comment": str(comment), "length": length}
1320        await self._request(
1321            RequestMethod.POST,
1322            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1323            json=payload,
1324            auth=access_token,
1325        )
1326
1327    async def unban_clan_member(
1328        self,
1329        access_token: str,
1330        /,
1331        group_id: int,
1332        membership_id: int,
1333        membership_type: typedefs.IntAnd[enums.MembershipType],
1334    ) -> None:
1335        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1336        await self._request(
1337            RequestMethod.POST,
1338            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1339            auth=access_token,
1340        )
1341
1342    async def kick_clan_member(
1343        self,
1344        access_token: str,
1345        /,
1346        group_id: int,
1347        membership_id: int,
1348        membership_type: typedefs.IntAnd[enums.MembershipType],
1349    ) -> typedefs.JSONObject:
1350        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1351        resp = await self._request(
1352            RequestMethod.POST,
1353            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1354            auth=access_token,
1355        )
1356        assert isinstance(resp, dict)
1357        return resp
1358
1359    async def edit_clan(
1360        self,
1361        access_token: str,
1362        /,
1363        group_id: int,
1364        *,
1365        name: typedefs.NoneOr[str] = None,
1366        about: typedefs.NoneOr[str] = None,
1367        motto: typedefs.NoneOr[str] = None,
1368        theme: typedefs.NoneOr[str] = None,
1369        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1370        is_public: typedefs.NoneOr[bool] = None,
1371        locale: typedefs.NoneOr[str] = None,
1372        avatar_image_index: typedefs.NoneOr[int] = None,
1373        membership_option: typedefs.NoneOr[
1374            typedefs.IntAnd[enums.MembershipOption]
1375        ] = None,
1376        allow_chat: typedefs.NoneOr[bool] = None,
1377        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1378        call_sign: typedefs.NoneOr[str] = None,
1379        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1380        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1381        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1382        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1383    ) -> None:
1384        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1385        payload = {
1386            "name": name,
1387            "about": about,
1388            "motto": motto,
1389            "theme": theme,
1390            "tags": tags,
1391            "isPublic": is_public,
1392            "avatarImageIndex": avatar_image_index,
1393            "isPublicTopicAdminOnly": is_public_topic_admin,
1394            "allowChat": allow_chat,
1395            "chatSecurity": chat_security,
1396            "callsign": call_sign,
1397            "homepage": homepage,
1398            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1399            "defaultPublicity": default_publicity,
1400            "locale": locale,
1401        }
1402        if membership_option is not None:
1403            payload["membershipOption"] = int(membership_option)
1404
1405        await self._request(
1406            RequestMethod.POST,
1407            f"GroupV2/{group_id}/Edit",
1408            json=payload,
1409            auth=access_token,
1410        )
1411
1412    async def edit_clan_options(
1413        self,
1414        access_token: str,
1415        /,
1416        group_id: int,
1417        *,
1418        invite_permissions_override: typedefs.NoneOr[bool] = None,
1419        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1420        host_guided_game_permission_override: typedefs.NoneOr[
1421            typing.Literal[0, 1, 2]
1422        ] = None,
1423        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1424        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1425    ) -> None:
1426
1427        payload = {
1428            "InvitePermissionOverride": invite_permissions_override,
1429            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1430            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1431            "UpdateBannerPermissionOverride": update_banner_permission_override,
1432            "JoinLevel": int(join_level) if join_level else None,
1433        }
1434
1435        await self._request(
1436            RequestMethod.POST,
1437            f"GroupV2/{group_id}/EditFounderOptions",
1438            json=payload,
1439            auth=access_token,
1440        )
1441
1442    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1443        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1444        resp = await self._request(
1445            RequestMethod.GET,
1446            "Social/Friends/",
1447            auth=access_token,
1448        )
1449        assert isinstance(resp, dict)
1450        return resp
1451
1452    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1453        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1454        resp = await self._request(
1455            RequestMethod.GET,
1456            "Social/Friends/Requests",
1457            auth=access_token,
1458        )
1459        assert isinstance(resp, dict)
1460        return resp
1461
1462    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1463        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1464        await self._request(
1465            RequestMethod.POST,
1466            f"Social/Friends/Requests/Accept/{member_id}",
1467            auth=access_token,
1468        )
1469
1470    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1472        await self._request(
1473            RequestMethod.POST,
1474            f"Social/Friends/Add/{member_id}",
1475            auth=access_token,
1476        )
1477
1478    async def decline_friend_request(
1479        self, access_token: str, /, member_id: int
1480    ) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1482        await self._request(
1483            RequestMethod.POST,
1484            f"Social/Friends/Requests/Decline/{member_id}",
1485            auth=access_token,
1486        )
1487
1488    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1489        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1490        await self._request(
1491            RequestMethod.POST,
1492            f"Social/Friends/Remove/{member_id}",
1493            auth=access_token,
1494        )
1495
1496    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1497        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1498        await self._request(
1499            RequestMethod.POST,
1500            f"Social/Friends/Requests/Remove/{member_id}",
1501            auth=access_token,
1502        )
1503
1504    async def approve_all_pending_group_users(
1505        self,
1506        access_token: str,
1507        /,
1508        group_id: int,
1509        message: undefined.UndefinedOr[str] = undefined.Undefined,
1510    ) -> None:
1511        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1512        await self._request(
1513            RequestMethod.POST,
1514            f"GroupV2/{group_id}/Members/ApproveAll",
1515            auth=access_token,
1516            json={"message": str(message)},
1517        )
1518
1519    async def deny_all_pending_group_users(
1520        self,
1521        access_token: str,
1522        /,
1523        group_id: int,
1524        *,
1525        message: undefined.UndefinedOr[str] = undefined.Undefined,
1526    ) -> None:
1527        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1528        await self._request(
1529            RequestMethod.POST,
1530            f"GroupV2/{group_id}/Members/DenyAll",
1531            auth=access_token,
1532            json={"message": str(message)},
1533        )
1534
1535    async def add_optional_conversation(
1536        self,
1537        access_token: str,
1538        /,
1539        group_id: int,
1540        *,
1541        name: undefined.UndefinedOr[str] = undefined.Undefined,
1542        security: typing.Literal[0, 1] = 0,
1543    ) -> None:
1544        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1545        payload = {"chatName": str(name), "chatSecurity": security}
1546        await self._request(
1547            RequestMethod.POST,
1548            f"GroupV2/{group_id}/OptionalConversations/Add",
1549            json=payload,
1550            auth=access_token,
1551        )
1552
1553    async def edit_optional_conversation(
1554        self,
1555        access_token: str,
1556        /,
1557        group_id: int,
1558        conversation_id: int,
1559        *,
1560        name: undefined.UndefinedOr[str] = undefined.Undefined,
1561        security: typing.Literal[0, 1] = 0,
1562        enable_chat: bool = False,
1563    ) -> None:
1564        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1565        payload = {
1566            "chatEnabled": enable_chat,
1567            "chatName": str(name),
1568            "chatSecurity": security,
1569        }
1570        await self._request(
1571            RequestMethod.POST,
1572            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1573            json=payload,
1574            auth=access_token,
1575        )
1576
1577    async def transfer_item(
1578        self,
1579        access_token: str,
1580        /,
1581        item_id: int,
1582        item_hash: int,
1583        character_id: int,
1584        member_type: typedefs.IntAnd[enums.MembershipType],
1585        *,
1586        stack_size: int = 1,
1587        vault: bool = False,
1588    ) -> None:
1589        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1590        payload = {
1591            "characterId": character_id,
1592            "membershipType": int(member_type),
1593            "itemId": item_id,
1594            "itemReferenceHash": item_hash,
1595            "stackSize": stack_size,
1596            "transferToVault": vault,
1597        }
1598        await self._request(
1599            RequestMethod.POST,
1600            "Destiny2/Actions/Items/TransferItem",
1601            json=payload,
1602            auth=access_token,
1603        )
1604
1605    async def pull_item(
1606        self,
1607        access_token: str,
1608        /,
1609        item_id: int,
1610        item_hash: int,
1611        character_id: int,
1612        member_type: typedefs.IntAnd[enums.MembershipType],
1613        *,
1614        stack_size: int = 1,
1615        vault: bool = False,
1616    ) -> None:
1617        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1618        payload = {
1619            "characterId": character_id,
1620            "membershipType": int(member_type),
1621            "itemId": item_id,
1622            "itemReferenceHash": item_hash,
1623            "stackSize": stack_size,
1624            "transferToVault": vault,
1625        }
1626        await self._request(
1627            RequestMethod.POST,
1628            "Destiny2/Actions/Items/PullFromPostmaster",
1629            json=payload,
1630            auth=access_token,
1631        )
1632
1633    async def fetch_fireteams(
1634        self,
1635        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1636        *,
1637        platform: typedefs.IntAnd[
1638            fireteams.FireteamPlatform
1639        ] = fireteams.FireteamPlatform.ANY,
1640        language: typing.Union[
1641            fireteams.FireteamLanguage, str
1642        ] = fireteams.FireteamLanguage.ALL,
1643        date_range: typedefs.IntAnd[
1644            fireteams.FireteamDate
1645        ] = fireteams.FireteamDate.ALL,
1646        page: int = 0,
1647        slots_filter: int = 0,
1648    ) -> typedefs.JSONObject:
1649        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1650        resp = await self._request(
1651            RequestMethod.GET,
1652            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1653        )
1654        assert isinstance(resp, dict)
1655        return resp
1656
1657    async def fetch_avaliable_clan_fireteams(
1658        self,
1659        access_token: str,
1660        group_id: int,
1661        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1662        *,
1663        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1664        language: typing.Union[fireteams.FireteamLanguage, str],
1665        date_range: typedefs.IntAnd[
1666            fireteams.FireteamDate
1667        ] = fireteams.FireteamDate.ALL,
1668        page: int = 0,
1669        public_only: bool = False,
1670        slots_filter: int = 0,
1671    ) -> typedefs.JSONObject:
1672        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1673        resp = await self._request(
1674            RequestMethod.GET,
1675            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1676            json={"langFilter": str(language)},
1677            auth=access_token,
1678        )
1679        assert isinstance(resp, dict)
1680        return resp
1681
1682    async def fetch_clan_fireteam(
1683        self, access_token: str, fireteam_id: int, group_id: int
1684    ) -> typedefs.JSONObject:
1685        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1686        resp = await self._request(
1687            RequestMethod.GET,
1688            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1689            auth=access_token,
1690        )
1691        assert isinstance(resp, dict)
1692        return resp
1693
1694    async def fetch_my_clan_fireteams(
1695        self,
1696        access_token: str,
1697        group_id: int,
1698        *,
1699        include_closed: bool = True,
1700        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1701        language: typing.Union[fireteams.FireteamLanguage, str],
1702        filtered: bool = True,
1703        page: int = 0,
1704    ) -> typedefs.JSONObject:
1705        payload = {"groupFilter": filtered, "langFilter": str(language)}
1706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1707        resp = await self._request(
1708            RequestMethod.GET,
1709            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1710            json=payload,
1711            auth=access_token,
1712        )
1713        assert isinstance(resp, dict)
1714        return resp
1715
1716    async def fetch_private_clan_fireteams(
1717        self, access_token: str, group_id: int, /
1718    ) -> int:
1719        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1720        resp = await self._request(
1721            RequestMethod.GET,
1722            f"Fireteam/Clan/{group_id}/ActiveCount",
1723            auth=access_token,
1724        )
1725        assert isinstance(resp, int)
1726        return resp
1727
1728    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1729        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1730        resp = await self._request(
1731            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1732        )
1733        assert isinstance(resp, dict)
1734        return resp
1735
1736    async def search_entities(
1737        self, name: str, entity_type: str, *, page: int = 0
1738    ) -> typedefs.JSONObject:
1739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1740        resp = await self._request(
1741            RequestMethod.GET,
1742            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1743            json={"page": page},
1744        )
1745        assert isinstance(resp, dict)
1746        return resp
1747
1748    async def fetch_unique_weapon_history(
1749        self,
1750        membership_id: int,
1751        character_id: int,
1752        membership_type: typedefs.IntAnd[enums.MembershipType],
1753    ) -> typedefs.JSONObject:
1754        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1755        resp = await self._request(
1756            RequestMethod.GET,
1757            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1758        )
1759        assert isinstance(resp, dict)
1760        return resp
1761
1762    async def fetch_item(
1763        self,
1764        member_id: int,
1765        item_id: int,
1766        membership_type: typedefs.IntAnd[enums.MembershipType],
1767        components: list[enums.ComponentType],
1768    ) -> typedefs.JSONObject:
1769        collector = _collect_components(components)
1770        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1771        resp = await self._request(
1772            RequestMethod.GET,
1773            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1774        )
1775        assert isinstance(resp, dict)
1776        return resp
1777
1778    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1779        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1780        resp = await self._request(
1781            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1782        )
1783        assert isinstance(resp, dict)
1784        return resp
1785
1786    async def fetch_available_locales(self) -> typedefs.JSONObject:
1787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1788        resp = await self._request(
1789            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1790        )
1791        assert isinstance(resp, dict)
1792        return resp
1793
1794    async def fetch_common_settings(self) -> typedefs.JSONObject:
1795        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1796        resp = await self._request(RequestMethod.GET, "Settings")
1797        assert isinstance(resp, dict)
1798        return resp
1799
1800    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1802        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1803        assert isinstance(resp, dict)
1804        return resp
1805
1806    async def fetch_global_alerts(
1807        self, *, include_streaming: bool = False
1808    ) -> typedefs.JSONArray:
1809        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1810        resp = await self._request(
1811            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1812        )
1813        assert isinstance(resp, list)
1814        return resp
1815
1816    async def awainitialize_request(
1817        self,
1818        access_token: str,
1819        type: typing.Literal[0, 1],
1820        membership_type: typedefs.IntAnd[enums.MembershipType],
1821        /,
1822        *,
1823        affected_item_id: typing.Optional[int] = None,
1824        character_id: typing.Optional[int] = None,
1825    ) -> typedefs.JSONObject:
1826        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1827
1828        body = {"type": type, "membershipType": int(membership_type)}
1829
1830        if affected_item_id is not None:
1831            body["affectedItemId"] = affected_item_id
1832
1833        if character_id is not None:
1834            body["characterId"] = character_id
1835
1836        resp = await self._request(
1837            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1838        )
1839        assert isinstance(resp, dict)
1840        return resp
1841
1842    async def awaget_action_token(
1843        self, access_token: str, correlation_id: str, /
1844    ) -> typedefs.JSONObject:
1845        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1846        resp = await self._request(
1847            RequestMethod.POST,
1848            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1849            auth=access_token,
1850        )
1851        assert isinstance(resp, dict)
1852        return resp
1853
1854    async def awa_provide_authorization_result(
1855        self,
1856        access_token: str,
1857        selection: int,
1858        correlation_id: str,
1859        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1860    ) -> int:
1861        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1862
1863        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1864
1865        resp = await self._request(
1866            RequestMethod.POST,
1867            "Destiny2/Awa/AwaProvideAuthorizationResult",
1868            json=body,
1869            auth=access_token,
1870        )
1871        assert isinstance(resp, int)
1872        return resp
1873
1874    async def fetch_vendors(
1875        self,
1876        access_token: str,
1877        character_id: int,
1878        membership_id: int,
1879        membership_type: typedefs.IntAnd[enums.MembershipType],
1880        /,
1881        components: list[enums.ComponentType],
1882        filter: typing.Optional[int] = None,
1883    ) -> typedefs.JSONObject:
1884        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1885        components_ = _collect_components(components)
1886        route = (
1887            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1888            f"/Character/{character_id}/Vendors/?components={components_}"
1889        )
1890
1891        if filter is not None:
1892            route = route + f"&filter={filter}"
1893
1894        resp = await self._request(
1895            RequestMethod.GET,
1896            route,
1897            auth=access_token,
1898        )
1899        assert isinstance(resp, dict)
1900        return resp
1901
1902    async def fetch_vendor(
1903        self,
1904        access_token: str,
1905        character_id: int,
1906        membership_id: int,
1907        membership_type: typedefs.IntAnd[enums.MembershipType],
1908        vendor_hash: int,
1909        /,
1910        components: list[enums.ComponentType],
1911    ) -> typedefs.JSONObject:
1912        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1913        components_ = _collect_components(components)
1914        resp = await self._request(
1915            RequestMethod.GET,
1916            (
1917                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1918                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1919            ),
1920            auth=access_token,
1921        )
1922        assert isinstance(resp, dict)
1923        return resp
1924
1925    async def fetch_application_api_usage(
1926        self,
1927        access_token: str,
1928        application_id: int,
1929        /,
1930        *,
1931        start: typing.Optional[datetime.datetime] = None,
1932        end: typing.Optional[datetime.datetime] = None,
1933    ) -> typedefs.JSONObject:
1934
1935        end_date, start_date = time.parse_date_range(end, start)
1936        resp = await self._request(
1937            RequestMethod.GET,
1938            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1939            auth=access_token,
1940        )
1941        assert isinstance(resp, dict)
1942        return resp
1943
1944    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1945        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1946        assert isinstance(resp, list)
1947        return resp
1948
1949    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1950        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1951        assert isinstance(resp, dict)
1952        return resp
1953
1954    async def fetch_content_by_id(
1955        self, id: int, locale: str, /, *, head: bool = False
1956    ) -> typedefs.JSONObject:
1957        resp = await self._request(
1958            RequestMethod.GET,
1959            f"Content/GetContentById/{id}/{locale}/",
1960            json={"head": head},
1961        )
1962        assert isinstance(resp, dict)
1963        return resp
1964
1965    async def fetch_content_by_tag_and_type(
1966        self, locale: str, tag: str, type: str, *, head: bool = False
1967    ) -> typedefs.JSONObject:
1968        resp = await self._request(
1969            RequestMethod.GET,
1970            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1971            json={"head": head},
1972        )
1973        assert isinstance(resp, dict)
1974        return resp
1975
1976    async def search_content_with_text(
1977        self,
1978        locale: str,
1979        /,
1980        content_type: str,
1981        search_text: str,
1982        tag: str,
1983        *,
1984        page: undefined.UndefinedOr[int] = undefined.Undefined,
1985        source: undefined.UndefinedOr[str] = undefined.Undefined,
1986    ) -> typedefs.JSONObject:
1987
1988        body: typedefs.JSONObject = {}
1989
1990        body["ctype"] = content_type
1991        body["searchtext"] = search_text
1992        body["tag"] = tag
1993
1994        if page is not undefined.Undefined:
1995            body["currentpage"] = page
1996        else:
1997            body["currentpage"] = 1
1998
1999        if source is not undefined.Undefined:
2000            body["source"] = source
2001        else:
2002            source = ""
2003        resp = await self._request(
2004            RequestMethod.GET, f"Content/Search/{locale}/", json=body
2005        )
2006        assert isinstance(resp, dict)
2007        return resp
2008
2009    async def search_content_by_tag_and_type(
2010        self,
2011        locale: str,
2012        tag: str,
2013        type: str,
2014        *,
2015        page: undefined.UndefinedOr[int] = undefined.Undefined,
2016    ) -> typedefs.JSONObject:
2017        body: typedefs.JSONObject = {}
2018        body["currentpage"] = 1 if page is undefined.Undefined else page
2019        resp = await self._request(
2020            RequestMethod.GET,
2021            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
2022            json=body,
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
2026
2027    async def search_help_articles(
2028        self, text: str, size: str, /
2029    ) -> typedefs.JSONObject:
2030        resp = await self._request(
2031            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2032        )
2033        assert isinstance(resp, dict)
2034        return resp
2035
2036    async def fetch_topics_page(
2037        self,
2038        category_filter: int,
2039        group: int,
2040        date_filter: int,
2041        sort: typing.Union[str, bytes],
2042        *,
2043        page: undefined.UndefinedOr[int] = undefined.Undefined,
2044        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2045        tag_filter: undefined.UndefinedOr[str] = undefined.Undefined,
2046    ) -> typedefs.JSONObject:
2047
2048        body: typedefs.JSONObject = {}
2049        if locales is not undefined.Undefined:
2050            body["locales"] = ",".join(str(locales))
2051        else:
2052            body["locales"] = ",".join([])
2053
2054        if tag_filter is not undefined.Undefined:
2055            body["tagstring"] = tag_filter
2056        else:
2057            body["tagstring"] = ""
2058
2059        page = 0 if page is not undefined.Undefined else page
2060
2061        resp = await self._request(
2062            RequestMethod.GET,
2063            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2064            json=body,
2065        )
2066        assert isinstance(resp, dict)
2067        return resp
2068
2069    async def fetch_core_topics_page(
2070        self,
2071        category_filter: int,
2072        date_filter: int,
2073        sort: typing.Union[str, bytes],
2074        *,
2075        page: undefined.UndefinedOr[int] = undefined.Undefined,
2076        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2077    ) -> typedefs.JSONObject:
2078        body: typedefs.JSONObject = {}
2079
2080        if locales is not undefined.Undefined:
2081            body["locales"] = ",".join(str(locales))
2082        else:
2083            body["locales"] = ",".join([])
2084
2085        resp = await self._request(
2086            RequestMethod.GET,
2087            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}"
2088            f"/{sort!s}/{date_filter}/{category_filter}/",
2089            json=body,
2090        )
2091        assert isinstance(resp, dict)
2092        return resp
2093
2094    async def fetch_posts_threaded_page(
2095        self,
2096        parent_post: bool,
2097        page: int,
2098        page_size: int,
2099        parent_post_id: int,
2100        reply_size: int,
2101        root_thread_mode: bool,
2102        sort_mode: int,
2103        show_banned: typing.Optional[str] = None,
2104    ) -> typedefs.JSONObject:
2105        resp = await self._request(
2106            RequestMethod.GET,
2107            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2108            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2109            json={"showbanned": show_banned},
2110        )
2111        assert isinstance(resp, dict)
2112        return resp
2113
2114    async def fetch_posts_threaded_page_from_child(
2115        self,
2116        child_id: bool,
2117        page: int,
2118        page_size: int,
2119        reply_size: int,
2120        root_thread_mode: bool,
2121        sort_mode: int,
2122        show_banned: typing.Optional[str] = None,
2123    ) -> typedefs.JSONObject:
2124        resp = await self._request(
2125            RequestMethod.GET,
2126            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2127            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2128            json={"showbanned": show_banned},
2129        )
2130        assert isinstance(resp, dict)
2131        return resp
2132
2133    async def fetch_post_and_parent(
2134        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2135    ) -> typedefs.JSONObject:
2136        resp = await self._request(
2137            RequestMethod.GET,
2138            f"Forum/GetPostAndParent/{child_id}/",
2139            json={"showbanned": show_banned},
2140        )
2141        assert isinstance(resp, dict)
2142        return resp
2143
2144    async def fetch_posts_and_parent_awaiting(
2145        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2146    ) -> typedefs.JSONObject:
2147        resp = await self._request(
2148            RequestMethod.GET,
2149            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2150            json={"showbanned": show_banned},
2151        )
2152        assert isinstance(resp, dict)
2153        return resp
2154
2155    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2156        resp = await self._request(
2157            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2158        )
2159        assert isinstance(resp, int)
2160        return resp
2161
2162    async def fetch_forum_tag_suggestions(
2163        self, partial_tag: str, /
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            "Forum/GetForumTagSuggestions/",
2168            json={"partialtag": partial_tag},
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
2172
2173    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2174        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2175        assert isinstance(resp, dict)
2176        return resp
2177
2178    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2179        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2180        assert isinstance(resp, list)
2181        return resp
2182
2183    async def fetch_recommended_groups(
2184        self,
2185        accecss_token: str,
2186        /,
2187        *,
2188        date_range: int = 0,
2189        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
2190    ) -> typedefs.JSONArray:
2191        resp = await self._request(
2192            RequestMethod.POST,
2193            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2194            auth=accecss_token,
2195        )
2196        assert isinstance(resp, list)
2197        return resp
2198
2199    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2200        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2201        assert isinstance(resp, dict)
2202        return resp
2203
2204    async def fetch_user_clan_invite_setting(
2205        self,
2206        access_token: str,
2207        /,
2208        membership_type: typedefs.IntAnd[enums.MembershipType],
2209    ) -> bool:
2210        resp = await self._request(
2211            RequestMethod.GET,
2212            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2213            auth=access_token,
2214        )
2215        assert isinstance(resp, bool)
2216        return resp
2217
2218    async def fetch_banned_group_members(
2219        self, access_token: str, group_id: int, /, *, page: int = 1
2220    ) -> typedefs.JSONObject:
2221        resp = await self._request(
2222            RequestMethod.GET,
2223            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2224            auth=access_token,
2225        )
2226        assert isinstance(resp, dict)
2227        return resp
2228
2229    async def fetch_pending_group_memberships(
2230        self, access_token: str, group_id: int, /, *, current_page: int = 1
2231    ) -> typedefs.JSONObject:
2232        resp = await self._request(
2233            RequestMethod.GET,
2234            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2235            auth=access_token,
2236        )
2237        assert isinstance(resp, dict)
2238        return resp
2239
2240    async def fetch_invited_group_memberships(
2241        self, access_token: str, group_id: int, /, *, current_page: int = 1
2242    ) -> typedefs.JSONObject:
2243        resp = await self._request(
2244            RequestMethod.GET,
2245            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2246            auth=access_token,
2247        )
2248        assert isinstance(resp, dict)
2249        return resp
2250
2251    async def invite_member_to_group(
2252        self,
2253        access_token: str,
2254        /,
2255        group_id: int,
2256        membership_id: int,
2257        membership_type: typedefs.IntAnd[enums.MembershipType],
2258        *,
2259        message: undefined.UndefinedOr[str] = undefined.Undefined,
2260    ) -> typedefs.JSONObject:
2261        resp = await self._request(
2262            RequestMethod.POST,
2263            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2264            auth=access_token,
2265            json={"message": str(message)},
2266        )
2267        assert isinstance(resp, dict)
2268        return resp
2269
2270    async def cancel_group_member_invite(
2271        self,
2272        access_token: str,
2273        /,
2274        group_id: int,
2275        membership_id: int,
2276        membership_type: typedefs.IntAnd[enums.MembershipType],
2277    ) -> typedefs.JSONObject:
2278        resp = await self._request(
2279            RequestMethod.POST,
2280            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2281            auth=access_token,
2282        )
2283        assert isinstance(resp, dict)
2284        return resp
2285
2286    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2287        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2288        assert isinstance(resp, dict)
2289        return resp
2290
2291    async def fetch_historical_stats(
2292        self,
2293        character_id: int,
2294        membership_id: int,
2295        membership_type: typedefs.IntAnd[enums.MembershipType],
2296        day_start: datetime.datetime,
2297        day_end: datetime.datetime,
2298        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2299        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2300        *,
2301        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2302    ) -> typedefs.JSONObject:
2303
2304        end, start = time.parse_date_range(day_end, day_start)
2305        resp = await self._request(
2306            RequestMethod.GET,
2307            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2308            json={
2309                "dayend": end,
2310                "daystart": start,
2311                "groups": [str(int(group)) for group in groups],
2312                "modes": [str(int(mode)) for mode in modes],
2313                "periodType": int(period_type),
2314            },
2315        )
2316        assert isinstance(resp, dict)
2317        return resp
2318
2319    async def fetch_historical_stats_for_account(
2320        self,
2321        membership_id: int,
2322        membership_type: typedefs.IntAnd[enums.MembershipType],
2323        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2324    ) -> typedefs.JSONObject:
2325        resp = await self._request(
2326            RequestMethod.GET,
2327            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2328            json={"groups": [str(int(group)) for group in groups]},
2329        )
2330        assert isinstance(resp, dict)
2331        return resp
2332
2333    async def fetch_aggregated_activity_stats(
2334        self,
2335        character_id: int,
2336        membership_id: int,
2337        membership_type: typedefs.IntAnd[enums.MembershipType],
2338        /,
2339    ) -> typedefs.JSONObject:
2340        resp = await self._request(
2341            RequestMethod.GET,
2342            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2343            f"Character/{character_id}/Stats/AggregateActivityStats/",
2344        )
2345        assert isinstance(resp, dict)
2346        return resp

A RESTful client implementation for Bungie's API.

This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.

This client is also used within aiobungie.Client which deserialize those returned JSON objects using the factory into Pythonic data classes objects which provide Python functionality.

Example
import aiobungie

async def main():
    async with aiobungie.RESTClient("TOKEN") as rest_client:
        req = await rest_client.fetch_clan_members(4389205)
        clan_members = req['results']
        for member in clan_members:
            for k, v in member['destinyUserInfo'].items():
                print(k, v)
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, max_ratelimit_retries: int = 3, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
411    def __init__(
412        self,
413        token: str,
414        /,
415        client_secret: typing.Optional[str] = None,
416        client_id: typing.Optional[int] = None,
417        *,
418        max_retries: int = 4,
419        max_ratelimit_retries: int = 3,
420        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
421    ) -> None:
422        self._session: typing.Optional[_Session] = None
423        self._lock: typing.Optional[asyncio.Lock] = None
424        self._client_secret = client_secret
425        self._client_id = client_id
426        self._token: str = token
427        self._max_retries = max_retries
428        self._max_rate_limit_retries = max_ratelimit_retries
429        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
430
431        self._set_debug_level(enable_debugging)
client_id: Optional[int]

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
445    @typing.final
446    async def close(self) -> None:
447        if self._session is not None:
448            await self._session.close()
449            self._session = None

Close this REST client session if it was acquired.

@typing.final
def enable_debugging( self, level: Union[Literal['TRACE'], bool, int] = False, file: Union[pathlib.Path, str, NoneType] = None, /) -> None:
451    @typing.final
452    def enable_debugging(
453        self,
454        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
455        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
456        /,
457    ) -> None:
458        self._set_debug_level(level, file)

Enables debugging for the REST calls.

Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
  • level (str | bool | int): The level of debugging to enable.
  • file (pathlib.Path | str | None): The file path to write the debug logs to. If provided.
@typing.final
async def static_request( self, method: Union[aiobungie.RequestMethod, str], path: str, *, auth: Optional[str] = None, json: Optional[dict[str, Any]] = None) -> Union[dict[str, Any], list[Any], bytes, int, bool, NoneType]:
460    @typing.final
461    async def static_request(
462        self,
463        method: typing.Union[RequestMethod, str],
464        path: str,
465        *,
466        auth: typing.Optional[str] = None,
467        json: typing.Optional[dict[str, typing.Any]] = None,
468    ) -> ResponseSig:
469        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (aiobungie.RequestMethod | str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
  • aiobungie.rest.ResponseSig: The response payload.
@typing.final
def build_oauth2_url(self, client_id: Optional[int] = None) -> Optional[str]:
471    @typing.final
472    def build_oauth2_url(
473        self, client_id: typing.Optional[int] = None
474    ) -> typing.Optional[str]:
475        client_id = client_id or self._client_id
476        if client_id is None:
477            return None
478
479        return url.OAUTH2_EP_BUILDER.format(
480            oauth_endpoint=url.OAUTH_EP,
481            client_id=client_id,
482            uuid=_uuid(),
483        )

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
  • str | None: If the client id was provided as a parameter or provided in aiobungie.RESTClient, A complete URL will be returned. Otherwise None will be returned.
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
715    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
716
717        if not isinstance(self._client_id, int):
718            raise TypeError(
719                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
720            )
721
722        if not isinstance(self._client_secret, str):
723            raise TypeError(
724                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
725            )
726
727        headers = {
728            "client_secret": self._client_secret,
729        }
730
731        data = (
732            f"grant_type=authorization_code&code={code}"
733            f"&client_id={self._client_id}&client_secret={self._client_secret}"
734        )
735
736        response = await self._request(
737            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
738        )
739        assert isinstance(response, dict)
740        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
742    async def refresh_access_token(
743        self, refresh_token: str, /
744    ) -> builders.OAuth2Response:
745        if not isinstance(self._client_id, int):
746            raise TypeError(
747                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
748            )
749
750        if not isinstance(self._client_secret, str):
751            raise TypeError(
752                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
753            )
754
755        data = {
756            "grant_type": "refresh_token",
757            "refresh_token": refresh_token,
758            "client_id": self._client_id,
759            "client_secret": self._client_secret,
760            "Content-Type": "application/x-www-form-urlencoded",
761        }
762
763        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
764        assert isinstance(response, dict)
765        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> dict[str, typing.Any]:
767    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
768        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
769        resp = await self._request(
770            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
771        )
772        assert isinstance(resp, dict)
773        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes(self) -> list[typing.Any]:
775    async def fetch_user_themes(self) -> typedefs.JSONArray:
776        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
777        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
778        assert isinstance(resp, list)
779        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>, /) -> dict[str, typing.Any]:
781    async def fetch_membership_from_id(
782        self,
783        id: int,
784        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
785        /,
786    ) -> typedefs.JSONObject:
787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
788        resp = await self._request(
789            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
790        )
791        assert isinstance(resp, dict)
792        return resp

Fetch Bungie user's memberships from their id.

Parameters
Returns
Raises
async def fetch_player( self, name: str, code: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, /) -> list[typing.Any]:
794    async def fetch_player(
795        self,
796        name: str,
797        code: int,
798        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
799        /,
800    ) -> typedefs.JSONArray:
801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
802        resp = await self._request(
803            RequestMethod.POST,
804            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
805            json={"displayName": name, "displayNameCode": code},
806        )
807        assert isinstance(resp, list)
808        return resp

Fetch a Destiny 2 Player.

Parameters
Returns
Raises
async def search_users(self, name: str, /) -> dict[str, typing.Any]:
810    async def search_users(self, name: str, /) -> typedefs.JSONObject:
811        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
812        resp = await self._request(
813            RequestMethod.POST,
814            "User/Search/GlobalName/0",
815            json={"displayNamePrefix": name},
816        )
817        assert isinstance(resp, dict)
818        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> dict[str, typing.Any]:
820    async def fetch_clan_from_id(
821        self, id: int, /, access_token: typing.Optional[str] = None
822    ) -> typedefs.JSONObject:
823        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
824        resp = await self._request(
825            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
826        )
827        assert isinstance(resp, dict)
828        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (typing.Optional[str]): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
830    async def fetch_clan(
831        self,
832        name: str,
833        /,
834        access_token: typing.Optional[str] = None,
835        *,
836        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
837    ) -> typedefs.JSONObject:
838        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
839        resp = await self._request(
840            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
841        )
842        assert isinstance(resp, dict)
843        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> dict[str, typing.Any]:
845    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
846        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
847        resp = await self._request(
848            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
849        )
850        assert isinstance(resp, dict)
851        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations(self, clan_id: int, /) -> list[typing.Any]:
853    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
854        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
855        resp = await self._request(
856            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
857        )
858        assert isinstance(resp, list)
859        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> dict[str, typing.Any]:
861    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
862        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
863        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
864        assert isinstance(resp, dict)
865        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
867    async def fetch_character(
868        self,
869        member_id: int,
870        membership_type: typedefs.IntAnd[enums.MembershipType],
871        character_id: int,
872        components: list[enums.ComponentType],
873        auth: typing.Optional[str] = None,
874    ) -> typedefs.JSONObject:
875        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
876        collector = _collect_components(components)
877        response = await self._request(
878            RequestMethod.GET,
879            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
880            f"Character/{character_id}/?components={collector}",
881            auth=auth,
882        )
883        assert isinstance(response, dict)
884        return response

Fetch a Destiny 2 player's characters.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> dict[str, typing.Any]:
886    async def fetch_activities(
887        self,
888        member_id: int,
889        character_id: int,
890        mode: typedefs.IntAnd[enums.GameMode],
891        membership_type: typedefs.IntAnd[
892            enums.MembershipType
893        ] = enums.MembershipType.ALL,
894        *,
895        page: int = 0,
896        limit: int = 1,
897    ) -> typedefs.JSONObject:
898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
899        resp = await self._request(
900            RequestMethod.GET,
901            f"Destiny2/{int(membership_type)}/Account/"
902            f"{member_id}/Character/{character_id}/Stats/Activities"
903            f"/?mode={int(mode)}&count={limit}&page={page}",
904        )
905        assert isinstance(resp, dict)
906        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
Returns
Raises
async def fetch_vendor_sales(self) -> dict[str, typing.Any]:
908    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
909        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
910        resp = await self._request(
911            RequestMethod.GET,
912            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
913        )
914        assert isinstance(resp, dict)
915        return resp
async def fetch_profile( self, membership_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
917    async def fetch_profile(
918        self,
919        membership_id: int,
920        type: typedefs.IntAnd[enums.MembershipType],
921        components: list[enums.ComponentType],
922        auth: typing.Optional[str] = None,
923    ) -> typedefs.JSONObject:
924        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
925        collector = _collect_components(components)
926        response = await self._request(
927            RequestMethod.GET,
928            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
929            auth=auth,
930        )
931        assert isinstance(response, dict)
932        return response

Fetch a bungie profile.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> dict[str, typing.Any]:
934    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
935        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
936        response = await self._request(
937            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
938        )
939        assert isinstance(response, dict)
940        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> dict[str, typing.Any]:
942    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
943        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
944        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
945        assert isinstance(resp, dict)
946        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> dict[str, typing.Any]:
948    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
949        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
950        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
951        assert isinstance(resp, dict)
952        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
954    async def fetch_groups_for_member(
955        self,
956        member_id: int,
957        member_type: typedefs.IntAnd[enums.MembershipType],
958        /,
959        *,
960        filter: int = 0,
961        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
962    ) -> typedefs.JSONObject:
963        resp = await self._request(
964            RequestMethod.GET,
965            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
966        )
967        assert isinstance(resp, dict)
968        return resp

Fetch the information about the groups for a member.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
970    async def fetch_potential_groups_for_member(
971        self,
972        member_id: int,
973        member_type: typedefs.IntAnd[enums.MembershipType],
974        /,
975        *,
976        filter: int = 0,
977        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
978    ) -> typedefs.JSONObject:
979        resp = await self._request(
980            RequestMethod.GET,
981            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
982        )
983        assert isinstance(resp, dict)
984        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> dict[str, typing.Any]:
 986    async def fetch_clan_members(
 987        self,
 988        clan_id: int,
 989        /,
 990        *,
 991        name: typing.Optional[str] = None,
 992        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 993    ) -> typedefs.JSONObject:
 994        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 995        resp = await self._request(
 996            RequestMethod.GET,
 997            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 998        )
 999        assert isinstance(resp, dict)
1000        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (builsins.int): The clans id
Other Parameters
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> dict[str, typing.Any]:
1002    async def fetch_hardlinked_credentials(
1003        self,
1004        credential: int,
1005        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
1006        /,
1007    ) -> typedefs.JSONObject:
1008        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1009        resp = await self._request(
1010            RequestMethod.GET,
1011            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
1012        )
1013        assert isinstance(resp, dict)
1014        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
Returns
async def fetch_user_credentials(self, access_token: str, membership_id: int, /) -> list[typing.Any]:
1016    async def fetch_user_credentials(
1017        self, access_token: str, membership_id: int, /
1018    ) -> typedefs.JSONArray:
1019        resp = await self._request(
1020            RequestMethod.GET,
1021            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
1022            auth=access_token,
1023        )
1024        assert isinstance(resp, list)
1025        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1027    async def insert_socket_plug(
1028        self,
1029        action_token: str,
1030        /,
1031        instance_id: int,
1032        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1033        character_id: int,
1034        membership_type: typedefs.IntAnd[enums.MembershipType],
1035    ) -> typedefs.JSONObject:
1036
1037        if isinstance(plug, builders.PlugSocketBuilder):
1038            plug = plug.collect()
1039
1040        body = {
1041            "actionToken": action_token,
1042            "itemInstanceId": instance_id,
1043            "plug": plug,
1044            "characterId": character_id,
1045            "membershipType": int(membership_type),
1046        }
1047        resp = await self._request(
1048            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1049        )
1050        assert isinstance(resp, dict)
1051        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1053    async def insert_socket_plug_free(
1054        self,
1055        access_token: str,
1056        /,
1057        instance_id: int,
1058        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1059        character_id: int,
1060        membership_type: typedefs.IntAnd[enums.MembershipType],
1061    ) -> typedefs.JSONObject:
1062
1063        if isinstance(plug, builders.PlugSocketBuilder):
1064            plug = plug.collect()
1065
1066        body = {
1067            "itemInstanceId": instance_id,
1068            "plug": plug,
1069            "characterId": character_id,
1070            "membershipType": int(membership_type),
1071        }
1072        resp = await self._request(
1073            RequestMethod.POST,
1074            "Destiny2/Actions/Items/InsertSocketPlugFree",
1075            json=body,
1076            auth=access_token,
1077        )
1078        assert isinstance(resp, dict)
1079        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1081    async def set_item_lock_state(
1082        self,
1083        access_token: str,
1084        state: bool,
1085        /,
1086        item_id: int,
1087        character_id: int,
1088        membership_type: typedefs.IntAnd[enums.MembershipType],
1089    ) -> int:
1090        body = {
1091            "state": state,
1092            "itemId": item_id,
1093            "characterId": character_id,
1094            "membership_type": int(membership_type),
1095        }
1096        response = await self._request(
1097            RequestMethod.POST,
1098            "Destiny2/Actions/Items/SetLockState",
1099            json=body,
1100            auth=access_token,
1101        )
1102        assert isinstance(response, int)
1103        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1105    async def set_quest_track_state(
1106        self,
1107        access_token: str,
1108        state: bool,
1109        /,
1110        item_id: int,
1111        character_id: int,
1112        membership_type: typedefs.IntAnd[enums.MembershipType],
1113    ) -> int:
1114        body = {
1115            "state": state,
1116            "itemId": item_id,
1117            "characterId": character_id,
1118            "membership_type": int(membership_type),
1119        }
1120        response = await self._request(
1121            RequestMethod.POST,
1122            "Destiny2/Actions/Items/SetTrackedState",
1123            json=body,
1124            auth=access_token,
1125        )
1126        assert isinstance(response, int)
1127        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> dict[str, typing.Any]:
1129    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1130        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1131        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1132        assert isinstance(path, dict)
1133        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1135    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1136        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1137        _ensure_manifest_language(language)
1138
1139        content = await self.fetch_manifest_path()
1140        resp = await self._request(
1141            RequestMethod.GET,
1142            content["mobileWorldContentPaths"][language],
1143            unwrapping="read",
1144            base=True,
1145        )
1146        assert isinstance(resp, bytes)
1147        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_manifest( self, language: str = 'en', name: str = 'manifest.sqlite3', *, force: bool = False) -> None:
1149    async def download_manifest(
1150        self,
1151        language: str = "en",
1152        name: str = "manifest.sqlite3",
1153        *,
1154        force: bool = False,
1155    ) -> None:
1156        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1157        if os.path.exists(name):
1158
1159            if force:
1160                _LOG.debug("Forcing manifest download.")
1161                os.remove(name)
1162
1163                return await self.download_manifest(language, name, force=force)
1164
1165            else:
1166                raise FileExistsError(
1167                    "Manifest file already exists, "
1168                    "If you want to force download, set the `force` parameter to `True`."
1169                )
1170
1171        _LOG.debug("Downloading manifest...")
1172        data_bytes = await self.read_manifest_bytes(language)
1173        await asyncio.get_running_loop().run_in_executor(
1174            None, _write_sqlite_bytes, data_bytes, name
1175        )

A helper method to download the manifest.

Note

This method downloads the sqlite database and not JSON. Use RESTInterface.download_json_manifest for the JSON version.

Parameters
  • language (str): The manifest language to download, Default is english.
  • name (str): The manifest database file name. Default is manifest.sqlite3
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get removed and a new one will being to download.
Returns
  • None
async def download_json_manifest(self, language: str = 'en') -> None:
1177    async def download_json_manifest(self, language: str = "en") -> None:
1178        _ensure_manifest_language(language)
1179
1180        _LOG.debug("Downloading manifest JSON...")
1181
1182        content = await self.fetch_manifest_path()
1183        json_bytes = await self._request(
1184            RequestMethod.GET,
1185            content["jsonWorldContentPaths"][language],
1186            unwrapping="read",
1187            base=True,
1188        )
1189
1190        await asyncio.get_running_loop().run_in_executor(
1191            None, _write_json_bytes, json_bytes
1192        )
1193        _LOG.debug("Finished downloading manifest JSON.")

Download the Bungie manifest json file.

Parameters
  • language (str): The language to download the manifest in.
async def fetch_manifest_version(self) -> str:
1195    async def fetch_manifest_version(self) -> str:
1196        return typing.cast(str, (await self.fetch_manifest_path())["version"])

Fetch the manifest version.

Returns
  • str: The manifest version.
@staticmethod
@helpers.deprecated(since='0.2.6a1', removed_in='0.2.6', use_instead='sqlite3.connect')
def connect_manifest( path: Optional[pathlib.Path] = None, connection: type[sqlite3.Connection] = ) -> sqlite3.Connection:
1198    @staticmethod
1199    @helpers.deprecated(
1200        since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect"
1201    )
1202    def connect_manifest(
1203        path: typing.Optional[pathlib.Path] = None,
1204        connection: type[sqlite3.Connection] = sqlite3.Connection,
1205    ) -> sqlite3.Connection:
1206        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1207        path = path or pathlib.Path("./manifest.sqlite3")
1208        if not path.exists():
1209            raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.")
1210        return connection(path.name)

A helper method to connect to the manifest database.

Parameters
  • path (typing.Optional[pathlib.Path]): An optional path to pass, The assumed path to connect to is './manifest.sqlite3'
  • connection (type[sqlite3.Connection]): An optional connection to pass, if not passed a new connection will be created.
Returns
  • sqlite3.Connection: An SQLite database connection.
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> dict[str, typing.Any]:
1212    async def fetch_linked_profiles(
1213        self,
1214        member_id: int,
1215        member_type: typedefs.IntAnd[enums.MembershipType],
1216        /,
1217        *,
1218        all: bool = False,
1219    ) -> typedefs.JSONObject:
1220        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1221        resp = await self._request(
1222            RequestMethod.GET,
1223            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1224        )
1225        assert isinstance(resp, dict)
1226        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether thry're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> dict[str, typing.Any]:
1228    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1229        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1230        resp = await self._request(
1231            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1232        )
1233        assert isinstance(resp, dict)
1234        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> dict[str, typing.Any]:
1236    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1237        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1238        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1239        assert isinstance(resp, dict)
1240        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> dict[str, typing.Any]:
1242    async def fetch_public_milestone_content(
1243        self, milestone_hash: int, /
1244    ) -> typedefs.JSONObject:
1245        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1246        resp = await self._request(
1247            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1248        )
1249        assert isinstance(resp, dict)
1250        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> dict[str, typing.Any]:
1252    async def fetch_current_user_memberships(
1253        self, access_token: str, /
1254    ) -> typedefs.JSONObject:
1255        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1256        resp = await self._request(
1257            RequestMethod.GET,
1258            "User/GetMembershipsForCurrentUser/",
1259            auth=access_token,
1260        )
1261        assert isinstance(resp, dict)
1262        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1264    async def equip_item(
1265        self,
1266        access_token: str,
1267        /,
1268        item_id: int,
1269        character_id: int,
1270        membership_type: typedefs.IntAnd[enums.MembershipType],
1271    ) -> None:
1272        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1273        payload = {
1274            "itemId": item_id,
1275            "characterId": character_id,
1276            "membershipType": int(membership_type),
1277        }
1278
1279        await self._request(
1280            RequestMethod.POST,
1281            "Destiny2/Actions/Items/EquipItem/",
1282            json=payload,
1283            auth=access_token,
1284        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def equip_items( self, access_token: str, /, item_ids: list[int], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1286    async def equip_items(
1287        self,
1288        access_token: str,
1289        /,
1290        item_ids: list[int],
1291        character_id: int,
1292        membership_type: typedefs.IntAnd[enums.MembershipType],
1293    ) -> None:
1294        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1295        payload = {
1296            "itemIds": item_ids,
1297            "characterId": character_id,
1298            "membershipType": int(membership_type),
1299        }
1300        await self._request(
1301            RequestMethod.POST,
1302            "Destiny2/Actions/Items/EquipItems/",
1303            json=payload,
1304            auth=access_token,
1305        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (list[int]): A list of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, length: int = 0, comment: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1307    async def ban_clan_member(
1308        self,
1309        access_token: str,
1310        /,
1311        group_id: int,
1312        membership_id: int,
1313        membership_type: typedefs.IntAnd[enums.MembershipType],
1314        *,
1315        length: int = 0,
1316        comment: undefined.UndefinedOr[str] = undefined.Undefined,
1317    ) -> None:
1318        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1319        payload = {"comment": str(comment), "length": length}
1320        await self._request(
1321            RequestMethod.POST,
1322            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1323            json=payload,
1324            auth=access_token,
1325        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
  • length (int): An optional ban length.
  • comment (aiobungie.UndefinedOr[str]): An optional comment to this ban. Default is UNDEFINED
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1327    async def unban_clan_member(
1328        self,
1329        access_token: str,
1330        /,
1331        group_id: int,
1332        membership_id: int,
1333        membership_type: typedefs.IntAnd[enums.MembershipType],
1334    ) -> None:
1335        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1336        await self._request(
1337            RequestMethod.POST,
1338            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1339            auth=access_token,
1340        )

Unbans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1342    async def kick_clan_member(
1343        self,
1344        access_token: str,
1345        /,
1346        group_id: int,
1347        membership_id: int,
1348        membership_type: typedefs.IntAnd[enums.MembershipType],
1349    ) -> typedefs.JSONObject:
1350        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1351        resp = await self._request(
1352            RequestMethod.POST,
1353            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1354            auth=access_token,
1355        )
1356        assert isinstance(resp, dict)
1357        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: Optional[str] = None, about: Optional[str] = None, motto: Optional[str] = None, theme: Optional[str] = None, tags: Optional[collections.abc.Sequence[str]] = None, is_public: Optional[bool] = None, locale: Optional[str] = None, avatar_image_index: Optional[int] = None, membership_option: Union[NoneType, int, aiobungie.MembershipOption] = None, allow_chat: Optional[bool] = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: Optional[str] = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: Optional[bool] = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: Optional[bool] = None) -> None:
1359    async def edit_clan(
1360        self,
1361        access_token: str,
1362        /,
1363        group_id: int,
1364        *,
1365        name: typedefs.NoneOr[str] = None,
1366        about: typedefs.NoneOr[str] = None,
1367        motto: typedefs.NoneOr[str] = None,
1368        theme: typedefs.NoneOr[str] = None,
1369        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1370        is_public: typedefs.NoneOr[bool] = None,
1371        locale: typedefs.NoneOr[str] = None,
1372        avatar_image_index: typedefs.NoneOr[int] = None,
1373        membership_option: typedefs.NoneOr[
1374            typedefs.IntAnd[enums.MembershipOption]
1375        ] = None,
1376        allow_chat: typedefs.NoneOr[bool] = None,
1377        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1378        call_sign: typedefs.NoneOr[str] = None,
1379        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1380        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1381        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1382        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1383    ) -> None:
1384        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1385        payload = {
1386            "name": name,
1387            "about": about,
1388            "motto": motto,
1389            "theme": theme,
1390            "tags": tags,
1391            "isPublic": is_public,
1392            "avatarImageIndex": avatar_image_index,
1393            "isPublicTopicAdminOnly": is_public_topic_admin,
1394            "allowChat": allow_chat,
1395            "chatSecurity": chat_security,
1396            "callsign": call_sign,
1397            "homepage": homepage,
1398            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1399            "defaultPublicity": default_publicity,
1400            "locale": locale,
1401        }
1402        if membership_option is not None:
1403            payload["membershipOption"] = int(membership_option)
1404
1405        await self._request(
1406            RequestMethod.POST,
1407            f"GroupV2/{group_id}/Edit",
1408            json=payload,
1409            auth=access_token,
1410        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: Optional[bool] = None, update_culture_permissionOverride: Optional[bool] = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: Optional[bool] = None, join_level: Union[NoneType, int, aiobungie.ClanMemberType] = None) -> None:
1412    async def edit_clan_options(
1413        self,
1414        access_token: str,
1415        /,
1416        group_id: int,
1417        *,
1418        invite_permissions_override: typedefs.NoneOr[bool] = None,
1419        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1420        host_guided_game_permission_override: typedefs.NoneOr[
1421            typing.Literal[0, 1, 2]
1422        ] = None,
1423        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1424        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1425    ) -> None:
1426
1427        payload = {
1428            "InvitePermissionOverride": invite_permissions_override,
1429            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1430            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1431            "UpdateBannerPermissionOverride": update_banner_permission_override,
1432            "JoinLevel": int(join_level) if join_level else None,
1433        }
1434
1435        await self._request(
1436            RequestMethod.POST,
1437            f"GroupV2/{group_id}/EditFounderOptions",
1438            json=payload,
1439            auth=access_token,
1440        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> dict[str, typing.Any]:
1442    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1443        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1444        resp = await self._request(
1445            RequestMethod.GET,
1446            "Social/Friends/",
1447            auth=access_token,
1448        )
1449        assert isinstance(resp, dict)
1450        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> dict[str, typing.Any]:
1452    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1453        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1454        resp = await self._request(
1455            RequestMethod.GET,
1456            "Social/Friends/Requests",
1457            auth=access_token,
1458        )
1459        assert isinstance(resp, dict)
1460        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1462    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1463        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1464        await self._request(
1465            RequestMethod.POST,
1466            f"Social/Friends/Requests/Accept/{member_id}",
1467            auth=access_token,
1468        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1470    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1472        await self._request(
1473            RequestMethod.POST,
1474            f"Social/Friends/Add/{member_id}",
1475            auth=access_token,
1476        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1478    async def decline_friend_request(
1479        self, access_token: str, /, member_id: int
1480    ) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1482        await self._request(
1483            RequestMethod.POST,
1484            f"Social/Friends/Requests/Decline/{member_id}",
1485            auth=access_token,
1486        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1488    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1489        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1490        await self._request(
1491            RequestMethod.POST,
1492            f"Social/Friends/Remove/{member_id}",
1493            auth=access_token,
1494        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1496    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1497        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1498        await self._request(
1499            RequestMethod.POST,
1500            f"Social/Friends/Requests/Remove/{member_id}",
1501            auth=access_token,
1502        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1504    async def approve_all_pending_group_users(
1505        self,
1506        access_token: str,
1507        /,
1508        group_id: int,
1509        message: undefined.UndefinedOr[str] = undefined.Undefined,
1510    ) -> None:
1511        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1512        await self._request(
1513            RequestMethod.POST,
1514            f"GroupV2/{group_id}/Members/ApproveAll",
1515            auth=access_token,
1516            json={"message": str(message)},
1517        )

Apporve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1519    async def deny_all_pending_group_users(
1520        self,
1521        access_token: str,
1522        /,
1523        group_id: int,
1524        *,
1525        message: undefined.UndefinedOr[str] = undefined.Undefined,
1526    ) -> None:
1527        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1528        await self._request(
1529            RequestMethod.POST,
1530            f"GroupV2/{group_id}/Members/DenyAll",
1531            auth=access_token,
1532            json={"message": str(message)},
1533        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0) -> None:
1535    async def add_optional_conversation(
1536        self,
1537        access_token: str,
1538        /,
1539        group_id: int,
1540        *,
1541        name: undefined.UndefinedOr[str] = undefined.Undefined,
1542        security: typing.Literal[0, 1] = 0,
1543    ) -> None:
1544        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1545        payload = {"chatName": str(name), "chatSecurity": security}
1546        await self._request(
1547            RequestMethod.POST,
1548            f"GroupV2/{group_id}/OptionalConversations/Add",
1549            json=payload,
1550            auth=access_token,
1551        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1553    async def edit_optional_conversation(
1554        self,
1555        access_token: str,
1556        /,
1557        group_id: int,
1558        conversation_id: int,
1559        *,
1560        name: undefined.UndefinedOr[str] = undefined.Undefined,
1561        security: typing.Literal[0, 1] = 0,
1562        enable_chat: bool = False,
1563    ) -> None:
1564        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1565        payload = {
1566            "chatEnabled": enable_chat,
1567            "chatName": str(name),
1568            "chatSecurity": security,
1569        }
1570        await self._request(
1571            RequestMethod.POST,
1572            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1573            json=payload,
1574            auth=access_token,
1575        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1577    async def transfer_item(
1578        self,
1579        access_token: str,
1580        /,
1581        item_id: int,
1582        item_hash: int,
1583        character_id: int,
1584        member_type: typedefs.IntAnd[enums.MembershipType],
1585        *,
1586        stack_size: int = 1,
1587        vault: bool = False,
1588    ) -> None:
1589        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1590        payload = {
1591            "characterId": character_id,
1592            "membershipType": int(member_type),
1593            "itemId": item_id,
1594            "itemReferenceHash": item_hash,
1595            "stackSize": stack_size,
1596            "transferToVault": vault,
1597        }
1598        await self._request(
1599            RequestMethod.POST,
1600            "Destiny2/Actions/Items/TransferItem",
1601            json=payload,
1602            auth=access_token,
1603        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to trasnfer this item to your valut or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1605    async def pull_item(
1606        self,
1607        access_token: str,
1608        /,
1609        item_id: int,
1610        item_hash: int,
1611        character_id: int,
1612        member_type: typedefs.IntAnd[enums.MembershipType],
1613        *,
1614        stack_size: int = 1,
1615        vault: bool = False,
1616    ) -> None:
1617        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1618        payload = {
1619            "characterId": character_id,
1620            "membershipType": int(member_type),
1621            "itemId": item_id,
1622            "itemReferenceHash": item_hash,
1623            "stackSize": stack_size,
1624            "transferToVault": vault,
1625        }
1626        await self._request(
1627            RequestMethod.POST,
1628            "Destiny2/Actions/Items/PullFromPostmaster",
1629            json=payload,
1630            auth=access_token,
1631        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to pill this item to your valut or not. Defaults to False.
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> dict[str, typing.Any]:
1633    async def fetch_fireteams(
1634        self,
1635        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1636        *,
1637        platform: typedefs.IntAnd[
1638            fireteams.FireteamPlatform
1639        ] = fireteams.FireteamPlatform.ANY,
1640        language: typing.Union[
1641            fireteams.FireteamLanguage, str
1642        ] = fireteams.FireteamLanguage.ALL,
1643        date_range: typedefs.IntAnd[
1644            fireteams.FireteamDate
1645        ] = fireteams.FireteamDate.ALL,
1646        page: int = 0,
1647        slots_filter: int = 0,
1648    ) -> typedefs.JSONObject:
1649        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1650        resp = await self._request(
1651            RequestMethod.GET,
1652            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1653        )
1654        assert isinstance(resp, dict)
1655        return resp

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> dict[str, typing.Any]:
1657    async def fetch_avaliable_clan_fireteams(
1658        self,
1659        access_token: str,
1660        group_id: int,
1661        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1662        *,
1663        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1664        language: typing.Union[fireteams.FireteamLanguage, str],
1665        date_range: typedefs.IntAnd[
1666            fireteams.FireteamDate
1667        ] = fireteams.FireteamDate.ALL,
1668        page: int = 0,
1669        public_only: bool = False,
1670        slots_filter: int = 0,
1671    ) -> typedefs.JSONObject:
1672        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1673        resp = await self._request(
1674            RequestMethod.GET,
1675            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1676            json={"langFilter": str(language)},
1677            auth=access_token,
1678        )
1679        assert isinstance(resp, dict)
1680        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> dict[str, typing.Any]:
1682    async def fetch_clan_fireteam(
1683        self, access_token: str, fireteam_id: int, group_id: int
1684    ) -> typedefs.JSONObject:
1685        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1686        resp = await self._request(
1687            RequestMethod.GET,
1688            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1689            auth=access_token,
1690        )
1691        assert isinstance(resp, dict)
1692        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> dict[str, typing.Any]:
1694    async def fetch_my_clan_fireteams(
1695        self,
1696        access_token: str,
1697        group_id: int,
1698        *,
1699        include_closed: bool = True,
1700        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1701        language: typing.Union[fireteams.FireteamLanguage, str],
1702        filtered: bool = True,
1703        page: int = 0,
1704    ) -> typedefs.JSONObject:
1705        payload = {"groupFilter": filtered, "langFilter": str(language)}
1706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1707        resp = await self._request(
1708            RequestMethod.GET,
1709            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1710            json=payload,
1711            auth=access_token,
1712        )
1713        assert isinstance(resp, dict)
1714        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1716    async def fetch_private_clan_fireteams(
1717        self, access_token: str, group_id: int, /
1718    ) -> int:
1719        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1720        resp = await self._request(
1721            RequestMethod.GET,
1722            f"Fireteam/Clan/{group_id}/ActiveCount",
1723            auth=access_token,
1724        )
1725        assert isinstance(resp, int)
1726        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> dict[str, typing.Any]:
1728    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1729        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1730        resp = await self._request(
1731            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1732        )
1733        assert isinstance(resp, dict)
1734        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> dict[str, typing.Any]:
1736    async def search_entities(
1737        self, name: str, entity_type: str, *, page: int = 0
1738    ) -> typedefs.JSONObject:
1739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1740        resp = await self._request(
1741            RequestMethod.GET,
1742            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1743            json={"page": page},
1744        )
1745        assert isinstance(resp, dict)
1746        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1748    async def fetch_unique_weapon_history(
1749        self,
1750        membership_id: int,
1751        character_id: int,
1752        membership_type: typedefs.IntAnd[enums.MembershipType],
1753    ) -> typedefs.JSONObject:
1754        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1755        resp = await self._request(
1756            RequestMethod.GET,
1757            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1758        )
1759        assert isinstance(resp, dict)
1760        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1762    async def fetch_item(
1763        self,
1764        member_id: int,
1765        item_id: int,
1766        membership_type: typedefs.IntAnd[enums.MembershipType],
1767        components: list[enums.ComponentType],
1768    ) -> typedefs.JSONObject:
1769        collector = _collect_components(components)
1770        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1771        resp = await self._request(
1772            RequestMethod.GET,
1773            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1774        )
1775        assert isinstance(resp, dict)
1776        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> dict[str, typing.Any]:
1778    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1779        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1780        resp = await self._request(
1781            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1782        )
1783        assert isinstance(resp, dict)
1784        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> dict[str, typing.Any]:
1786    async def fetch_available_locales(self) -> typedefs.JSONObject:
1787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1788        resp = await self._request(
1789            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1790        )
1791        assert isinstance(resp, dict)
1792        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> dict[str, typing.Any]:
1794    async def fetch_common_settings(self) -> typedefs.JSONObject:
1795        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1796        resp = await self._request(RequestMethod.GET, "Settings")
1797        assert isinstance(resp, dict)
1798        return resp

Fetch the common settings used by Bungie's envirotment.

Returns
async def fetch_user_systems_overrides(self) -> dict[str, typing.Any]:
1800    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1802        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1803        assert isinstance(resp, dict)
1804        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts(self, *, include_streaming: bool = False) -> list[typing.Any]:
1806    async def fetch_global_alerts(
1807        self, *, include_streaming: bool = False
1808    ) -> typedefs.JSONArray:
1809        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1810        resp = await self._request(
1811            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1812        )
1813        assert isinstance(resp, list)
1814        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: Union[int, aiobungie.MembershipType], /, *, affected_item_id: Optional[int] = None, character_id: Optional[int] = None) -> dict[str, typing.Any]:
1816    async def awainitialize_request(
1817        self,
1818        access_token: str,
1819        type: typing.Literal[0, 1],
1820        membership_type: typedefs.IntAnd[enums.MembershipType],
1821        /,
1822        *,
1823        affected_item_id: typing.Optional[int] = None,
1824        character_id: typing.Optional[int] = None,
1825    ) -> typedefs.JSONObject:
1826        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1827
1828        body = {"type": type, "membershipType": int(membership_type)}
1829
1830        if affected_item_id is not None:
1831            body["affectedItemId"] = affected_item_id
1832
1833        if character_id is not None:
1834            body["characterId"] = character_id
1835
1836        resp = await self._request(
1837            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1838        )
1839        assert isinstance(resp, dict)
1840        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token(self, access_token: str, correlation_id: str, /) -> dict[str, typing.Any]:
1842    async def awaget_action_token(
1843        self, access_token: str, correlation_id: str, /
1844    ) -> typedefs.JSONObject:
1845        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1846        resp = await self._request(
1847            RequestMethod.POST,
1848            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1849            auth=access_token,
1850        )
1851        assert isinstance(resp, dict)
1852        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[typing.Union[str, bytes]]) -> int:
1854    async def awa_provide_authorization_result(
1855        self,
1856        access_token: str,
1857        selection: int,
1858        correlation_id: str,
1859        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1860    ) -> int:
1861        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1862
1863        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1864
1865        resp = await self._request(
1866            RequestMethod.POST,
1867            "Destiny2/Awa/AwaProvideAuthorizationResult",
1868            json=body,
1869            auth=access_token,
1870        )
1871        assert isinstance(resp, int)
1872        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str, bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /, components: list[aiobungie.ComponentType], filter: Optional[int] = None) -> dict[str, typing.Any]:
1874    async def fetch_vendors(
1875        self,
1876        access_token: str,
1877        character_id: int,
1878        membership_id: int,
1879        membership_type: typedefs.IntAnd[enums.MembershipType],
1880        /,
1881        components: list[enums.ComponentType],
1882        filter: typing.Optional[int] = None,
1883    ) -> typedefs.JSONObject:
1884        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1885        components_ = _collect_components(components)
1886        route = (
1887            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1888            f"/Character/{character_id}/Vendors/?components={components_}"
1889        )
1890
1891        if filter is not None:
1892            route = route + f"&filter={filter}"
1893
1894        resp = await self._request(
1895            RequestMethod.GET,
1896            route,
1897            auth=access_token,
1898        )
1899        assert isinstance(resp, dict)
1900        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], vendor_hash: int, /, components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1902    async def fetch_vendor(
1903        self,
1904        access_token: str,
1905        character_id: int,
1906        membership_id: int,
1907        membership_type: typedefs.IntAnd[enums.MembershipType],
1908        vendor_hash: int,
1909        /,
1910        components: list[enums.ComponentType],
1911    ) -> typedefs.JSONObject:
1912        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1913        components_ = _collect_components(components)
1914        resp = await self._request(
1915            RequestMethod.GET,
1916            (
1917                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1918                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1919            ),
1920            auth=access_token,
1921        )
1922        assert isinstance(resp, dict)
1923        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None) -> dict[str, typing.Any]:
1925    async def fetch_application_api_usage(
1926        self,
1927        access_token: str,
1928        application_id: int,
1929        /,
1930        *,
1931        start: typing.Optional[datetime.datetime] = None,
1932        end: typing.Optional[datetime.datetime] = None,
1933    ) -> typedefs.JSONObject:
1934
1935        end_date, start_date = time.parse_date_range(end, start)
1936        resp = await self._request(
1937            RequestMethod.GET,
1938            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1939            auth=access_token,
1940        )
1941        assert isinstance(resp, dict)
1942        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications(self) -> list[typing.Any]:
1944    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1945        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1946        assert isinstance(resp, list)
1947        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> dict[str, typing.Any]:
1949    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1950        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1951        assert isinstance(resp, dict)
1952        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> dict[str, typing.Any]:
1954    async def fetch_content_by_id(
1955        self, id: int, locale: str, /, *, head: bool = False
1956    ) -> typedefs.JSONObject:
1957        resp = await self._request(
1958            RequestMethod.GET,
1959            f"Content/GetContentById/{id}/{locale}/",
1960            json={"head": head},
1961        )
1962        assert isinstance(resp, dict)
1963        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> dict[str, typing.Any]:
1965    async def fetch_content_by_tag_and_type(
1966        self, locale: str, tag: str, type: str, *, head: bool = False
1967    ) -> typedefs.JSONObject:
1968        resp = await self._request(
1969            RequestMethod.GET,
1970            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1971            json={"head": head},
1972        )
1973        assert isinstance(resp, dict)
1974        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, source: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1976    async def search_content_with_text(
1977        self,
1978        locale: str,
1979        /,
1980        content_type: str,
1981        search_text: str,
1982        tag: str,
1983        *,
1984        page: undefined.UndefinedOr[int] = undefined.Undefined,
1985        source: undefined.UndefinedOr[str] = undefined.Undefined,
1986    ) -> typedefs.JSONObject:
1987
1988        body: typedefs.JSONObject = {}
1989
1990        body["ctype"] = content_type
1991        body["searchtext"] = search_text
1992        body["tag"] = tag
1993
1994        if page is not undefined.Undefined:
1995            body["currentpage"] = page
1996        else:
1997            body["currentpage"] = 1
1998
1999        if source is not undefined.Undefined:
2000            body["source"] = source
2001        else:
2002            source = ""
2003        resp = await self._request(
2004            RequestMethod.GET, f"Content/Search/{locale}/", json=body
2005        )
2006        assert isinstance(resp, dict)
2007        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED) -> dict[str, typing.Any]:
2009    async def search_content_by_tag_and_type(
2010        self,
2011        locale: str,
2012        tag: str,
2013        type: str,
2014        *,
2015        page: undefined.UndefinedOr[int] = undefined.Undefined,
2016    ) -> typedefs.JSONObject:
2017        body: typedefs.JSONObject = {}
2018        body["currentpage"] = 1 if page is undefined.Undefined else page
2019        resp = await self._request(
2020            RequestMethod.GET,
2021            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
2022            json=body,
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
async def search_help_articles(self, text: str, size: str, /) -> dict[str, typing.Any]:
2027    async def search_help_articles(
2028        self, text: str, size: str, /
2029    ) -> typedefs.JSONObject:
2030        resp = await self._request(
2031            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2032        )
2033        assert isinstance(resp, dict)
2034        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED, tag_filter: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2036    async def fetch_topics_page(
2037        self,
2038        category_filter: int,
2039        group: int,
2040        date_filter: int,
2041        sort: typing.Union[str, bytes],
2042        *,
2043        page: undefined.UndefinedOr[int] = undefined.Undefined,
2044        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2045        tag_filter: undefined.UndefinedOr[str] = undefined.Undefined,
2046    ) -> typedefs.JSONObject:
2047
2048        body: typedefs.JSONObject = {}
2049        if locales is not undefined.Undefined:
2050            body["locales"] = ",".join(str(locales))
2051        else:
2052            body["locales"] = ",".join([])
2053
2054        if tag_filter is not undefined.Undefined:
2055            body["tagstring"] = tag_filter
2056        else:
2057            body["tagstring"] = ""
2058
2059        page = 0 if page is not undefined.Undefined else page
2060
2061        resp = await self._request(
2062            RequestMethod.GET,
2063            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2064            json=body,
2065        )
2066        assert isinstance(resp, dict)
2067        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED) -> dict[str, typing.Any]:
2069    async def fetch_core_topics_page(
2070        self,
2071        category_filter: int,
2072        date_filter: int,
2073        sort: typing.Union[str, bytes],
2074        *,
2075        page: undefined.UndefinedOr[int] = undefined.Undefined,
2076        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2077    ) -> typedefs.JSONObject:
2078        body: typedefs.JSONObject = {}
2079
2080        if locales is not undefined.Undefined:
2081            body["locales"] = ",".join(str(locales))
2082        else:
2083            body["locales"] = ",".join([])
2084
2085        resp = await self._request(
2086            RequestMethod.GET,
2087            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}"
2088            f"/{sort!s}/{date_filter}/{category_filter}/",
2089            json=body,
2090        )
2091        assert isinstance(resp, dict)
2092        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2094    async def fetch_posts_threaded_page(
2095        self,
2096        parent_post: bool,
2097        page: int,
2098        page_size: int,
2099        parent_post_id: int,
2100        reply_size: int,
2101        root_thread_mode: bool,
2102        sort_mode: int,
2103        show_banned: typing.Optional[str] = None,
2104    ) -> typedefs.JSONObject:
2105        resp = await self._request(
2106            RequestMethod.GET,
2107            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2108            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2109            json={"showbanned": show_banned},
2110        )
2111        assert isinstance(resp, dict)
2112        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2114    async def fetch_posts_threaded_page_from_child(
2115        self,
2116        child_id: bool,
2117        page: int,
2118        page_size: int,
2119        reply_size: int,
2120        root_thread_mode: bool,
2121        sort_mode: int,
2122        show_banned: typing.Optional[str] = None,
2123    ) -> typedefs.JSONObject:
2124        resp = await self._request(
2125            RequestMethod.GET,
2126            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2127            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2128            json={"showbanned": show_banned},
2129        )
2130        assert isinstance(resp, dict)
2131        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2133    async def fetch_post_and_parent(
2134        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2135    ) -> typedefs.JSONObject:
2136        resp = await self._request(
2137            RequestMethod.GET,
2138            f"Forum/GetPostAndParent/{child_id}/",
2139            json={"showbanned": show_banned},
2140        )
2141        assert isinstance(resp, dict)
2142        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2144    async def fetch_posts_and_parent_awaiting(
2145        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2146    ) -> typedefs.JSONObject:
2147        resp = await self._request(
2148            RequestMethod.GET,
2149            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2150            json={"showbanned": show_banned},
2151        )
2152        assert isinstance(resp, dict)
2153        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2155    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2156        resp = await self._request(
2157            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2158        )
2159        assert isinstance(resp, int)
2160        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> dict[str, typing.Any]:
2162    async def fetch_forum_tag_suggestions(
2163        self, partial_tag: str, /
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            "Forum/GetForumTagSuggestions/",
2168            json={"partialtag": partial_tag},
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
async def fetch_poll(self, topic_id: int, /) -> dict[str, typing.Any]:
2173    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2174        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2175        assert isinstance(resp, dict)
2176        return resp
async def fetch_recuirement_thread_summaries(self) -> list[typing.Any]:
2178    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2179        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2180        assert isinstance(resp, list)
2181        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2199    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2200        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2201        assert isinstance(resp, dict)
2202        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: Union[int, aiobungie.MembershipType]) -> bool:
2204    async def fetch_user_clan_invite_setting(
2205        self,
2206        access_token: str,
2207        /,
2208        membership_type: typedefs.IntAnd[enums.MembershipType],
2209    ) -> bool:
2210        resp = await self._request(
2211            RequestMethod.GET,
2212            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2213            auth=access_token,
2214        )
2215        assert isinstance(resp, bool)
2216        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> dict[str, typing.Any]:
2218    async def fetch_banned_group_members(
2219        self, access_token: str, group_id: int, /, *, page: int = 1
2220    ) -> typedefs.JSONObject:
2221        resp = await self._request(
2222            RequestMethod.GET,
2223            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2224            auth=access_token,
2225        )
2226        assert isinstance(resp, dict)
2227        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2229    async def fetch_pending_group_memberships(
2230        self, access_token: str, group_id: int, /, *, current_page: int = 1
2231    ) -> typedefs.JSONObject:
2232        resp = await self._request(
2233            RequestMethod.GET,
2234            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2235            auth=access_token,
2236        )
2237        assert isinstance(resp, dict)
2238        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2240    async def fetch_invited_group_memberships(
2241        self, access_token: str, group_id: int, /, *, current_page: int = 1
2242    ) -> typedefs.JSONObject:
2243        resp = await self._request(
2244            RequestMethod.GET,
2245            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2246            auth=access_token,
2247        )
2248        assert isinstance(resp, dict)
2249        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2251    async def invite_member_to_group(
2252        self,
2253        access_token: str,
2254        /,
2255        group_id: int,
2256        membership_id: int,
2257        membership_type: typedefs.IntAnd[enums.MembershipType],
2258        *,
2259        message: undefined.UndefinedOr[str] = undefined.Undefined,
2260    ) -> typedefs.JSONObject:
2261        resp = await self._request(
2262            RequestMethod.POST,
2263            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2264            auth=access_token,
2265            json={"message": str(message)},
2266        )
2267        assert isinstance(resp, dict)
2268        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
2270    async def cancel_group_member_invite(
2271        self,
2272        access_token: str,
2273        /,
2274        group_id: int,
2275        membership_id: int,
2276        membership_type: typedefs.IntAnd[enums.MembershipType],
2277    ) -> typedefs.JSONObject:
2278        resp = await self._request(
2279            RequestMethod.POST,
2280            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2281            auth=access_token,
2282        )
2283        assert isinstance(resp, dict)
2284        return resp
async def fetch_historical_definition(self) -> dict[str, typing.Any]:
2286    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2287        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2288        assert isinstance(resp, dict)
2289        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], day_start: datetime.datetime, day_end: datetime.datetime, groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]], modes: collections.abc.Sequence[typing.Union[int, aiobungie.GameMode]], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> dict[str, typing.Any]:
2291    async def fetch_historical_stats(
2292        self,
2293        character_id: int,
2294        membership_id: int,
2295        membership_type: typedefs.IntAnd[enums.MembershipType],
2296        day_start: datetime.datetime,
2297        day_end: datetime.datetime,
2298        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2299        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2300        *,
2301        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2302    ) -> typedefs.JSONObject:
2303
2304        end, start = time.parse_date_range(day_end, day_start)
2305        resp = await self._request(
2306            RequestMethod.GET,
2307            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2308            json={
2309                "dayend": end,
2310                "daystart": start,
2311                "groups": [str(int(group)) for group in groups],
2312                "modes": [str(int(mode)) for mode in modes],
2313                "periodType": int(period_type),
2314            },
2315        )
2316        assert isinstance(resp, dict)
2317        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (list[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]]) -> dict[str, typing.Any]:
2319    async def fetch_historical_stats_for_account(
2320        self,
2321        membership_id: int,
2322        membership_type: typedefs.IntAnd[enums.MembershipType],
2323        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2324    ) -> typedefs.JSONObject:
2325        resp = await self._request(
2326            RequestMethod.GET,
2327            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2328            json={"groups": [str(int(group)) for group in groups]},
2329        )
2330        assert isinstance(resp, dict)
2331        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /) -> dict[str, typing.Any]:
2333    async def fetch_aggregated_activity_stats(
2334        self,
2335        character_id: int,
2336        membership_id: int,
2337        membership_type: typedefs.IntAnd[enums.MembershipType],
2338        /,
2339    ) -> typedefs.JSONObject:
2340        resp = await self._request(
2341            RequestMethod.GET,
2342            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2343            f"Character/{character_id}/Stats/AggregateActivityStats/",
2344        )
2345        assert isinstance(resp, dict)
2346        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
class RESTPool:
234class RESTPool:
235    """Pool of `RESTClient` instances.
236
237    This allows to create multiple instances of `RESTClient`s that can be acquired
238    which share the same connector and metadata.
239
240    Example
241    -------
242    ```py
243    import aiobungie
244
245    client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
246
247    # Using a context manager to acquire an instance
248    # of the pool and close the connection after finishing.
249
250    async with client_pool.acquire() as client:
251        await client.download_manifest()
252        return client.build_oauth2_url()
253
254    async with client_pool.acquire() as client:
255        new_tokens = await client.refresh_access_token("token")
256        # Tokens now can be used from any pool.
257        client.metadata['tokens'] = new_tokens
258    ```
259
260    Parameters
261    ----------
262    token : `str`
263        A valid application token from Bungie's developer portal.
264
265    Other Parameters
266    ----------------
267    max_retries : `int`
268        The max retries number to retry if the request hit a `5xx` status code.
269    max_ratelimit_retries : `int`
270        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
271    client_secret : `typing.Optional[str]`
272        An optional application client secret,
273        This is only needed if you're fetching OAuth2 tokens with this client.
274    client_id : `typing.Optional[int]`
275        An optional application client id,
276        This is only needed if you're fetching OAuth2 tokens with this client.
277    enable_debugging : `bool | str`
278        Whether to enable logging responses or not.
279
280    Logging Levels
281    --------------
282    * `False`: This will disable logging.
283    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
284    Like the response status, route, taken time and so on.
285    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
286    """
287
288    __slots__ = (
289        "_token",
290        "_max_retries",
291        "_client_secret",
292        "_client_id",
293        "_max_rate_limit_retries",
294        "_metadata",
295        "_enable_debug",
296    )
297
298    # Looks like mypy doesn't like this.
299    if typing.TYPE_CHECKING:
300        _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int]
301
302    def __init__(
303        self,
304        token: str,
305        /,
306        client_secret: typing.Optional[str] = None,
307        client_id: typing.Optional[int] = None,
308        *,
309        max_retries: int = 4,
310        max_rate_limit_retries: int = 3,
311        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
312    ) -> None:
313        self._client_secret = client_secret
314        self._client_id = client_id
315        self._token: str = token
316        self._max_retries = max_retries
317        self._max_rate_limit_retries = max_rate_limit_retries
318        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
319        self._enable_debug = enable_debugging
320
321    @property
322    def client_id(self) -> typing.Optional[int]:
323        return self._client_id
324
325    @property
326    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
327        """Pool's Metadata. This is different from client instance metadata."""
328        return self._metadata
329
330    @typing.final
331    def acquire(self) -> RESTClient:
332        """Acquires a new `RESTClient` instance from this REST pool.
333
334        Returns
335        -------
336        `RESTClient`
337            An instance of a REST client.
338        """
339        instance = RESTClient(
340            self._token,
341            client_secret=self._client_secret,
342            client_id=self._client_id,
343            max_retries=self._max_retries,
344            max_ratelimit_retries=self._max_rate_limit_retries,
345            enable_debugging=self._enable_debug,
346        )
347        return instance

Pool of RESTClient instances.

This allows to create multiple instances of RESTClients that can be acquired which share the same connector and metadata.

Example
import aiobungie

client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')

# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.

async with client_pool.acquire() as client:
    await client.download_manifest()
    return client.build_oauth2_url()

async with client_pool.acquire() as client:
    new_tokens = await client.refresh_access_token("token")
    # Tokens now can be used from any pool.
    client.metadata['tokens'] = new_tokens
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, max_rate_limit_retries: int = 3, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
302    def __init__(
303        self,
304        token: str,
305        /,
306        client_secret: typing.Optional[str] = None,
307        client_id: typing.Optional[int] = None,
308        *,
309        max_retries: int = 4,
310        max_rate_limit_retries: int = 3,
311        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
312    ) -> None:
313        self._client_secret = client_secret
314        self._client_id = client_id
315        self._token: str = token
316        self._max_retries = max_retries
317        self._max_rate_limit_retries = max_rate_limit_retries
318        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
319        self._enable_debug = enable_debugging
client_id: Optional[int]
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> aiobungie.RESTClient:
330    @typing.final
331    def acquire(self) -> RESTClient:
332        """Acquires a new `RESTClient` instance from this REST pool.
333
334        Returns
335        -------
336        `RESTClient`
337            An instance of a REST client.
338        """
339        instance = RESTClient(
340            self._token,
341            client_secret=self._client_secret,
342            client_id=self._client_id,
343            max_retries=self._max_retries,
344            max_ratelimit_retries=self._max_rate_limit_retries,
345            enable_debugging=self._enable_debug,
346        )
347        return instance

Acquires a new RESTClient instance from this REST pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
496@typing.final
497class Race(int, Enum):
498    """An Enum for Destiny races."""
499
500    HUMAN = 0
501    AWOKEN = 1
502    EXO = 2
503    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
148@typing.final
149class Raid(int, Enum):
150    """An Enum for all available raids in Destiny 2."""
151
152    DSC = 910380154
153    """Deep Stone Crypt"""
154
155    LW = 2122313384
156    """Last Wish"""
157
158    VOG = 3881495763
159    """Normal Valut of Glass"""
160
161    GOS = 3458480158
162    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
213@attrs.define(auto_exc=True)
214class RateLimitedError(HTTPError):
215    """Raised when being hit with ratelimits."""
216
217    http_status: http.HTTPStatus = attrs.field(
218        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
219    )
220    """The request response http status."""
221
222    url: typedefs.StrOrURL
223    """The URL/endpoint caused this error."""
224
225    body: typing.Any
226    """The response body."""
227
228    retry_after: float = attrs.field(default=0.0)
229    """The amount of seconds you need to wait before retrying to requests."""
230
231    message: str = attrs.field(init=False)
232    """A Bungie human readable message describes the cause of the error."""
233
234    @message.default  # type: ignore
235    def _(self) -> str:
236        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
237
238    def __str__(self) -> str:
239        return self.message

Raised when being hit with ratelimits.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class RecordState(aiobungie.Flag):
49@typing.final
50class RecordState(enums.Flag):
51    """An enum for records component states."""
52
53    NONE = 0
54    REDEEMED = 1
55    UNAVAILABLE = 2
56    OBJECTIVE_NOT_COMPLETED = 4
57    OBSCURED = 8
58    INVISIBLE = 16
59    ENTITLEMENT_UNOWNED = 32
60    CAN_EQUIP_TITLE = 64

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
691@typing.final
692class Relationship(int, Enum):
693    """An enum for bungie friends relationship types."""
694
695    UNKNOWN = 0
696    FRIEND = 1
697    INCOMING_REQUEST = 2
698    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RequestMethod(builtins.str, aiobungie.Enum):
215class RequestMethod(str, enums.Enum):
216    """HTTP request methods enum."""
217
218    GET = "GET"
219    """GET methods."""
220    POST = "POST"
221    """POST methods."""
222    PUT = "PUT"
223    """PUT methods."""
224    PATCH = "PATCH"
225    """PATCH methods."""
226    DELETE = "DELETE"
227    """DELETE methods"""

HTTP request methods enum.

GET = <RequestMethod.GET: GET>

GET methods.

POST = <RequestMethod.POST: POST>

POST methods.

PUT = <RequestMethod.PUT: PUT>

PUT methods.

PATCH = <RequestMethod.PATCH: PATCH>

PATCH methods.

DELETE = <RequestMethod.DELETE: DELETE>

DELETE methods

Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
208@attrs.define(auto_exc=True)
209class ResponseError(HTTPException):
210    """Standard HTTP responses exception."""

Standard HTTP responses exception.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class Stat(builtins.int, aiobungie.Enum):
518@typing.final
519class Stat(int, Enum):
520    """An Enum for Destiny 2 character stats."""
521
522    NONE = 0
523    MOBILITY = 2996146975
524    RESILIENCE = 392767087
525    RECOVERY = 1943323491
526    DISCIPLINE = 1735777505
527    INTELLECT = 144602215
528    STRENGTH = 4244567218
529    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
633@typing.final
634class TierType(int, Enum):
635    """An enum for a Destiny 2 item tier type."""
636
637    UNKNOWN = 0
638    CURRENCY = 1
639    BASIC = 2
640    COMMON = 3
641    RARE = 4
642    SUPERIOR = 5
643    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
743@typing.final
744class TransferStatus(Flag):
745    """An enum for items transfer statuses."""
746
747    CAN_TRANSFER = 0
748    """The item can be transferred."""
749    IS_EQUIPPED = 1
750    """You can't transfer since the item is equipped."""
751    NOT_TRASNFERRABLE = 2
752    """This item can not be transferred."""
753    COULD_BE_TRANSFERRED = 4
754    """You can trasnfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can trasnfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
151@attrs.define(auto_exc=True)
152class Unauthorized(HTTPException):
153    """Unauthorized access."""
154
155    http_status: http.HTTPStatus = attrs.field(
156        default=http.HTTPStatus.UNAUTHORIZED, init=False
157    )

Unauthorized access.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
Undefined = UNDEFINED
UndefinedOr = typing.Union[aiobungie.UndefinedType, +_T]
class UndefinedType:
33class UndefinedType:
34    """An `UNDEFINED` type."""
35
36    __instance: typing.Optional[UndefinedType] = None
37
38    def __bool__(self) -> typing.Literal[False]:
39        return False
40
41    def __int__(self) -> typing.Literal[0]:
42        return 0
43
44    def __repr__(self) -> str:
45        return "UNDEFINED"
46
47    def __str__(self) -> str:
48        return "UNDEFINED"
49
50    def __new__(cls) -> UndefinedType:
51        if cls.__instance is None:
52            o = super().__new__(cls)
53            cls.__instance = o
54        return cls.__instance

An UNDEFINED type.

UndefinedType()
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
75@typing.final
76class ValueUIStyle(int, enums.Enum):
77    AUTOMATIC = 0
78    FRACTION = 1
79    CHECK_BOX = 2
80    PERCENTAGE = 3
81    DATETIME = 4
82    FRACTION_FLOAT = 5
83    INTEGER = 6
84    TIME_DURATION = 7
85    HIDDEN = 8
86    MULTIPLIER = 9
87    GREEN_PIPS = 10
88    RED_PIPS = 11
89    EXPLICIT_PERCENTAGE = 12
90    RAW_FLOAT = 13
91    LEVEL_AND_REWARD = 14

An enumeration.

AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
245@typing.final
246class Vendor(int, Enum):
247    """An Enum for all available vendors in Destiny 2."""
248
249    ZAVALA = 69482069
250    XUR = 2190858386
251    BANSHE = 672118013
252    SPIDER = 863940356
253    SHAXX = 3603221665
254    KADI = 529635856
255    """Postmaster exo."""
256    YUNA = 1796504621
257    """Asia servers only."""
258    EVERVERSE = 3361454721
259    AMANDA = 460529231
260    """Amanda holiday"""
261    CROW = 3611983588
262    HAWTHORNE = 3347378076
263    ADA1 = 350061650
264    DRIFTER = 248695599
265    IKORA = 1976548992
266    SAINT = 765357505
267    """Saint-14"""
268    ERIS_MORN = 1616085565
269    SHAW_HAWN = 1816541247
270    """COSMODROME Guy"""
271    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
532@typing.final
533class WeaponType(int, Enum):
534    """Enums for The three Destiny Weapon Types"""
535
536    NONE = 0
537    KINETIC = 1498876634
538    ENERGY = 2465295065
539    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), (3, 11, 0, 'alpha', 0), 16777216)
def into_iter( iterable: collections.abc.Iterable[~Item]) -> aiobungie.FlatIterator[~Item]:
594def into_iter(
595    iterable: collections.Iterable[Item],
596) -> FlatIterator[Item]:
597    """Converts an iterable into an flat iterator.
598
599    Example
600    -------
601    >>> sequence = [1,2,3]
602    >>> async for item in aiobungie.into_iter(sequence).reversed():
603            print(item)
604    # 3
605    # 2
606    # 1
607
608    Parameters
609    ----------
610    iterable: `typing.Iterable[Item]`
611        The iterable to convert.
612
613    Raises
614    ------
615    `StopIteration`
616        If no elements are left in the iterator.
617    """
618    return FlatIterator(iterable)

Converts an iterable into an flat iterator.

Example
>>> sequence = [1,2,3]
>>> async for item in aiobungie.into_iter(sequence).reversed():
        print(item)
<h1 id="3">3</h1>

2

1

Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def raise_error( response: aiohttp.client_reqrep.ClientResponse) -> aiobungie.AiobungieError:
242async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError:
243    """Generates and raise exceptions on error responses."""
244
245    # Not a JSON response, raise immediately.
246
247    # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized
248    # request with a dummy access token. I can't really do anything about this..
249    if response.content_type != "application/json":
250        return HTTPError(
251            f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}",
252            http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
253        )
254
255    body = await response.json()
256    message: str = body.get("Message", "UNDEFINED_MESSAGE")
257    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
258    message_data: dict[str, str] = body.get("MessageData", {})
259    throttle_seconds: int = body.get("ThrottleSeconds", 0)
260    error_code: int = body.get("ErrorCode", 0)
261
262    # Standard HTTP status.
263    if response.status == http.HTTPStatus.NOT_FOUND:
264        return NotFound(
265            message=message,
266            error_code=error_code,
267            throttle_seconds=throttle_seconds,
268            url=str(response.real_url),
269            body=body,
270            headers=response.headers,
271            error_status=error_status,
272            message_data=message_data,
273        )
274
275    elif response.status == http.HTTPStatus.FORBIDDEN:
276        return Forbidden(
277            message=message,
278            error_code=error_code,
279            throttle_seconds=throttle_seconds,
280            url=str(response.real_url),
281            body=body,
282            headers=response.headers,
283            error_status=error_status,
284            message_data=message_data,
285        )
286
287    elif response.status == http.HTTPStatus.UNAUTHORIZED:
288        return Unauthorized(
289            message=message,
290            error_code=error_code,
291            throttle_seconds=throttle_seconds,
292            url=str(response.real_url),
293            body=body,
294            headers=response.headers,
295            error_status=error_status,
296            message_data=message_data,
297        )
298
299    elif response.status == http.HTTPStatus.BAD_REQUEST:
300        # Membership needs to be alone.
301        if error_status == "InvalidParameters":
302            return MembershipTypeError(
303                message=message,
304                body=body,
305                headers=response.headers,
306                url=str(response.url),
307                membership_type=message_data["membershipType"],
308                required_membership=message_data["membershipInfo.membershipType"],
309                membership_id=int(message_data["membershipId"]),
310            )
311        return BadRequest(
312            message=message,
313            body=body,
314            headers=response.headers,
315            url=str(response.url),
316        )
317
318    status = http.HTTPStatus(response.status)
319
320    if 400 <= status < 500:
321        return ResponseError(
322            message=message,
323            error_code=error_code,
324            throttle_seconds=throttle_seconds,
325            url=str(response.real_url),
326            body=body,
327            headers=response.headers,
328            error_status=error_status,
329            message_data=message_data,
330            http_status=status,
331        )
332
333    # Need to self handle ~5xx errors
334    elif 500 <= status < 600:
335        # No API key or method requires OAuth2 most likely.
336        if error_status in {
337            "ApiKeyMissingFromRequest",
338            "WebAuthRequired",
339            "ApiInvalidOrExpiredKey",
340            "AuthenticationInvalid",
341            "AuthorizationCodeInvalid",
342        }:
343            return Unauthorized(
344                message=message,
345                error_code=error_code,
346                throttle_seconds=throttle_seconds,
347                url=str(response.real_url),
348                body=body,
349                headers=response.headers,
350                error_status=error_status,
351                message_data=message_data,
352            )
353
354        # Anything contains not found.
355        elif (
356            "NotFound" in error_status or error_status == "UserCannotFindRequestedUser"
357        ):
358            return NotFound(
359                message=message,
360                error_code=error_code,
361                throttle_seconds=throttle_seconds,
362                url=str(response.real_url),
363                body=body,
364                headers=response.headers,
365                error_status=error_status,
366                message_data=message_data,
367            )
368
369        # Other 5xx errors.
370        else:
371            return InternalServerError(
372                message=message,
373                error_code=error_code,
374                throttle_seconds=throttle_seconds,
375                url=str(response.real_url),
376                body=body,
377                headers=response.headers,
378                error_status=error_status,
379                message_data=message_data,
380                http_status=status,
381            )
382    # Something else.
383    else:
384        return HTTPException(
385            message=message,
386            error_code=error_code,
387            throttle_seconds=throttle_seconds,
388            url=str(response.real_url),
389            body=body,
390            headers=response.headers,
391            error_status=error_status,
392            message_data=message_data,
393            http_status=status,
394        )

Generates and raise exceptions on error responses.

def stringify_http_message(headers: 'collections.Mapping[str, str]') -> str:
397def stringify_http_message(headers: collections.Mapping[str, str]) -> str:
398    return (
399        "{ \n"
400        + "\n".join(  # noqa: W503
401            f"{f'   {key}'}: {value}"
402            if key not in ("Authorization", "X-API-KEY")
403            else f"   {key}: HIDDEN_TOKEN"
404            for key, value in headers.items()
405        )
406        + "\n}"  # noqa: W503
407    )